亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Redis入門必備指南

發布時間:2020-05-11 15:01:04 來源:億速云 閱讀:368 作者:Leah 欄目:編程語言

這篇文章為大家帶來有關Redis入門必備指南的詳細介紹。大部分命令行知識點都是大家經常用到的,為此分享給大家做個參考。一起跟隨小編過來看看吧。

由于數據庫的緩存一般是針對查詢的內容,而且粒度也比較小,一般只有表中的數據沒有發生變動的時候,數據庫的緩存才會產生作用。

但這并不能減少業務邏輯對數據庫的增刪改操作的 IO 壓力,因此緩存技術應運而生,該技術實現了對熱點數據的高速緩存,可以大大緩解后端數據庫的壓力。

主流應用架構

Redis入門必備指南


客戶端在對數據庫發起請求時,先到緩存層查看是否有所需的數據,如果緩存層存有客戶端所需的數據,則直接從緩存層返回,否則進行穿透查詢,對數據庫進行查詢。

如果在數據庫中查詢到該數據,則將該數據回寫到緩存層,以便下次客戶端再次查詢能夠直接從緩存層獲取數據。

緩存中間件 Memcache 和 Redis 的區別

Memcache 的代碼層類似 Hash,特點如下:

  • 支持簡單數據類型

  • 不支持數據持久化存儲

  • 不支持主從

  • 不支持分片

Redis 特點如下:

  • 數據類型豐富

  • 支持數據磁盤持久化存儲

  • 支持主從

  • 支持分片

為什么 Redis 能這么快

Redis 的效率很高,官方給出的數據是 100000+QPS,這是因為:

  • Redis 完全基于內存,絕大部分請求是純粹的內存操作,執行效率高。

  • Redis 使用單進程單線程模型的(K,V)數據庫,將數據存儲在內存中,存取均不會受到硬盤 IO 的限制,因此其執行速度極快。另外單線程也能處理高并發請求,還可以避免頻繁上下文切換和鎖的競爭,如果想要多核運行也可以啟動多個實例。

  • 數據結構簡單,對數據操作也簡單,Redis 不使用表,不會強制用戶對各個關系進行關聯,不會有復雜的關系限制,其存儲結構就是鍵值對,類似于 HashMap,HashMap 最大的優點就是存取的時間復雜度為 O(1)。

  • Redis 使用多路 I/O 復用模型,為非阻塞 IO。

注:Redis 采用的 I/O 多路復用函數:epoll/kqueue/evport/select。

選用策略:

  • 因地制宜,優先選擇時間復雜度為 O(1) 的 I/O 多路復用函數作為底層實現。

  • 由于 Select 要遍歷每一個 IO,所以其時間復雜度為 O(n),通常被作為保底方案。

  • 基于 React 設計模式監聽 I/O 事件。

Redis 的數據類型

String

最基本的數據類型,其值最大可存儲 512M,二進制安全(Redis 的 String 可以包含任何二進制數據,包含 jpg 對象等)。

Redis入門必備指南


注:如果重復寫入 key 相同的鍵值對,后寫入的會將之前寫入的覆蓋。

Hash

String 元素組成的字典,適用于存儲對象。

Redis入門必備指南


List

列表,按照 String 元素插入順序排序。其順序為后進先出。由于其具有棧的特性,所以可以實現如“最新消息排行榜”這類的功能。

Redis入門必備指南


Set

String 元素組成的無序集合,通過哈希表實現(增刪改查時間復雜度為 O(1)),不允許重復。

Redis入門必備指南


另外,當我們使用 Smembers 遍歷 Set 中的元素時,其順序也是不確定的,是通過 Hash 運算過后的結果。

Redis 還對集合提供了求交集、并集、差集等操作,可以實現如同共同關注,共同好友等功能。

Sorted Set

通過分數來為集合中的成員進行從小到大的排序。

Redis入門必備指南


更高級的 Redis 類型

用于計數的 HyperLogLog、用于支持存儲地理位置信息的 Geo。

從海量 Key 里查詢出某一個固定前綴的 Key

假設 Redis 中有十億條 Key,如何從這么多 Key 中找到固定前綴的 Key?

方法 1:使用 Keys [pattern]:查找所有符合給定模式 Pattern 的 Key

使用 Keys [pattern] 指令可以找到所有符合 Pattern 條件的 Key,但是 Keys 會一次性返回所有符合條件的 Key,所以會造成 Redis 的卡頓。

假設 Redis 此時正在生產環境下,使用該命令就會造成隱患,另外如果一次性返回所有 Key,對內存的消耗在某些條件下也是巨大的。

例:

keys test* //返回所有以test為前綴的key

方法 2:使用 SCAN cursor [MATCH pattern] [COUNT count]

注:

  • cursor:游標

  • MATCH pattern:查詢 Key 的條件

  • Count:返回的條數

SCAN 是一個基于游標的迭代器,需要基于上一次的游標延續之前的迭代過程。

SCAN 以 0 作為游標,開始一次新的迭代,直到命令返回游標 0 完成一次遍歷。

此命令并不保證每次執行都返回某個給定數量的元素,甚至會返回 0 個元素,但只要游標不是 0,程序都不會認為 SCAN 命令結束,但是返回的元素數量大概率符合 Count 參數。另外,SCAN 支持模糊查詢。

例:

SCAN 0 MATCH test* COUNT 10 //每次返回10條以test為前綴的key

如何通過 Redis 實現分布式鎖

分布式鎖

分布式鎖是控制分布式系統之間共同訪問共享資源的一種鎖的實現。如果一個系統,或者不同系統的不同主機之間共享某個資源時,往往需要互斥,來排除干擾,滿足數據一致性。

分布式鎖需要解決的問題如下:

  • 互斥性:任意時刻只有一個客戶端獲取到鎖,不能有兩個客戶端同時獲取到鎖。

  • 安全性:鎖只能被持有該鎖的客戶端刪除,不能由其他客戶端刪除。

  • 死鎖:獲取鎖的客戶端因為某些原因而宕機繼而無法釋放鎖,其他客戶端再也無法獲取鎖而導致死鎖,此時需要有特殊機制來避免死鎖。

  • 容錯:當各個節點,如某個 Redis 節點宕機的時候,客戶端仍然能夠獲取鎖或釋放鎖。

如何使用 Redis 實現分布式鎖

使用 SETNX 實現,SETNX key value:如果 Key 不存在,則創建并賦值。

該命令時間復雜度為 O(1),如果設置成功,則返回 1,否則返回 0。

Redis入門必備指南


由于 SETNX 指令操作簡單,且是原子性的,所以初期的時候經常被人們作為分布式鎖,我們在應用的時候,可以在某個共享資源區之前先使用 SETNX 指令,查看是否設置成功。

如果設置成功則說明前方沒有客戶端正在訪問該資源,如果設置失敗則說明有客戶端正在訪問該資源,那么當前客戶端就需要等待。

但是如果真的這么做,就會存在一個問題,因為 SETNX 是長久存在的,所以假設一個客戶端正在訪問資源,并且上鎖,那么當這個客戶端結束訪問時,該鎖依舊存在,后來者也無法成功獲取鎖,這個該如何解決呢?

由于 SETNX 并不支持傳入 EXPIRE 參數,所以我們可以直接使用 EXPIRE 指令來對特定的 Key 來設置過期時間。

用法:

EXPIRE key seconds

Redis入門必備指南


程序:

RedisService redisService = SpringUtils.getBean(RedisService.class);
long status = redisService.setnx(key,"1");if(status == 1){
 redisService.expire(key,expire);
 doOcuppiedWork();
}

這段程序存在的問題:假設程序運行到第二行出現異常,那么程序來不及設置過期時間就結束了,則 Key 會一直存在,等同于鎖一直被持有無法釋放。

出現此問題的根本原因為:原子性得不到滿足。

解決:從 Redis 2.6.12 版本開始,我們就可以使用 Set 操作,將 SETNX 和 EXPIRE 融合在一起執行,具體做法如下:

  • EX second:設置鍵的過期時間為 Second 秒。

  • PX millisecond:設置鍵的過期時間為 MilliSecond 毫秒。

  • NX:只在鍵不存在時,才對鍵進行設置操作。

  • XX:只在鍵已經存在時,才對鍵進行設置操作。

SET KEY value [EX seconds] [PX milliseconds] [NX|XX]

注:SET 操作成功完成時才會返回 OK,否則返回 nil。

有了 SET 我們就可以在程序中使用類似下面的代碼實現分布式鎖了:

RedisService redisService = SpringUtils.getBean(RedisService.class);
String result = redisService.set(lockKey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,expireTime);if("OK.equals(result)"){
 doOcuppiredWork();
}

如何實現異步隊列

①使用 Redis 中的 List 作為隊列

使用上文所說的 Redis 的數據結構中的 List 作為隊列 Rpush 生產消息,LPOP 消費消息。

Redis入門必備指南


此時我們可以看到,該隊列是使用 Rpush 生產隊列,使用 LPOP 消費隊列。

在這個生產者-消費者隊列里,當 LPOP 沒有消息時,證明該隊列中沒有元素,并且生產者還沒有來得及生產新的數據。

缺點:LPOP 不會等待隊列中有值之后再消費,而是直接進行消費。

彌補:可以通過在應用層引入 Sleep 機制去調用 LPOP 重試。

②使用 BLPOP key [key…] timeout

BLPOP key [key …] timeout:阻塞直到隊列有消息或者超時。

Redis入門必備指南


Redis入門必備指南


Redis入門必備指南


缺點:按照此種方法,我們生產后的數據只能提供給各個單一消費者消費。能否實現生產一次就能讓多個消費者消費呢?

③Pub/Sub:主題訂閱者模式

發送者(Pub)發送消息,訂閱者(Sub)接收消息。訂閱者可以訂閱任意數量的頻道。

Redis入門必備指南


Pub/Sub模式的缺點:消息的發布是無狀態的,無法保證可達。對于發布者來說,消息是“即發即失”的。

此時如果某個消費者在生產者發布消息時下線,重新上線之后,是無法接收該消息的,要解決該問題需要使用專業的消息隊列,如 Kafka…此處不再贅述。

Redis 持久化

什么是持久化

持久化,即將數據持久存儲,而不因斷電或其他各種復雜外部環境影響數據的完整性。

由于 Redis 將數據存儲在內存而不是磁盤中,所以內存一旦斷電,Redis 中存儲的數據也隨即消失,這往往是用戶不期望的,所以 Redis 有持久化機制來保證數據的安全性。

Redis 如何做持久化

Redis 目前有兩種持久化方式,即 RDB 和 AOF,RDB 是通過保存某個時間點的全量數據快照實現數據的持久化,當恢復數據時,直接通過 RDB 文件中的快照,將數據恢復。

RDB(快照)持久化

RDB持久化會在某個特定的間隔保存那個時間點的全量數據的快照。

RDB 配置文件,redis.conf:

 save 900 1 #在900s內如果有1條數據被寫入,則產生一次快照。
 save 300 10 #在300s內如果有10條數據被寫入,則產生一次快照
 save 60 10000 #在60s內如果有10000條數據被寫入,則產生一次快照
 stop-writes-on-bgsave-error yes 
 #stop-writes-on-bgsave-error :
 如果為yes則表示,當備份進程出錯的時候,
 主進程就停止進行接受新的寫入操作,這樣是為了保護持久化的數據一致性的問題。

①RDB 的創建與載入

SAVE:阻塞 Redis 的服務器進程,直到 RDB 文件被創建完畢。SAVE 命令很少被使用,因為其會阻塞主線程來保證快照的寫入,由于 Redis 是使用一個主線程來接收所有客戶端請求,這樣會阻塞所有客戶端請求。

BGSAVE:該指令會 Fork 出一個子進程來創建 RDB 文件,不阻塞服務器進程,子進程接收請求并創建 RDB 快照,父進程繼續接收客戶端的請求。

子進程在完成文件的創建時會向父進程發送信號,父進程在接收客戶端請求的過程中,在一定的時間間隔通過輪詢來接收子進程的信號。

我們也可以通過使用 lastsave 指令來查看 BGSAVE 是否執行成功,lastsave 可以返回最后一次執行成功 BGSAVE 的時間。

②自動化觸發 RDB 持久化的方式

自動化觸發RDB持久化的方式如下:

  • 根據 redis.conf 配置里的 SAVE m n 定時觸發(實際上使用的是 BGSAVE)。

  • 主從復制時,主節點自動觸發。

  • 執行 Debug Reload。

  • 執行 Shutdown 且沒有開啟 AOF 持久化。

③BGSAVE 的原理

Redis入門必備指南


啟動:

  • 檢查是否存在子進程正在執行 AOF 或者 RDB 的持久化任務。如果有則返回 false。

  • 調用 Redis 源碼中的 rdbSaveBackground 方法,方法中執行 fork() 產生子進程執行 RDB 操作。

  • 關于 fork() 中的 Copy-On-Write。

fork() 在 Linux 中創建子進程采用 Copy-On-Write(寫時拷貝技術),即如果有多個調用者同時要求相同資源(如內存或磁盤上的數據存儲)。

他們會共同獲取相同的指針指向相同的資源,直到某個調用者試圖修改資源的內容時,系統才會真正復制一份專用副本給調用者,而其他調用者所見到的最初的資源仍然保持不變。

④RDB 持久化方式的缺點

RDB 持久化方式的缺點如下:

  • 內存數據全量同步,數據量大的狀況下,會由于 I/O 而嚴重影響性能。

  • 可能會因為 Redis 宕機而丟失從當前至最近一次快照期間的數據。

AOF 持久化:保存寫狀態

AOF 持久化是通過保存 Redis 的寫狀態來記錄數據庫的。

相對 RDB 來說,RDB 持久化是通過備份數據庫的狀態來記錄數據庫,而 AOF 持久化是備份數據庫接收到的指令:

  • AOF 記錄除了查詢以外的所有變更數據庫狀態的指令。

  • 以增量的形式追加保存到 AOF 文件中。

開啟 AOF 持久化

①打開 redis.conf 配置文件,將 appendonly 屬性改為 yes。

②修改 appendfsync 屬性,該屬性可以接收三種參數,分別是 always,everysec,no。

always 表示總是即時將緩沖區內容寫入 AOF 文件當中,everysec 表示每隔一秒將緩沖區內容寫入 AOF 文件,no 表示將寫入文件操作交由操作系統決定。

一般來說,操作系統考慮效率問題,會等待緩沖區被填滿再將緩沖區數據寫入 AOF 文件中。

 appendonly yes

 #appendsync always
 appendfsync everysec # appendfsync no

日志重寫解決 AOF 文件不斷增大

隨著寫操作的不斷增加,AOF 文件會越來越大。假設遞增一個計數器 100 次,如果使用 RDB 持久化方式,我們只要保存最終結果 100 即可。

而 AOF 持久化方式需要記錄下這 100 次遞增操作的指令,而事實上要恢復這條記錄,只需要執行一條命令就行,所以那一百條命令實際可以精簡為一條。

Redis 支持這樣的功能,在不中斷前臺服務的情況下,可以重寫 AOF 文件,同樣使用到了 COW(寫時拷貝)。

重寫過程如下:

  • 調用 fork(),創建一個子進程。

  • 子進程把新的 AOF 寫到一個臨時文件里,不依賴原來的 AOF 文件。

  • 主進程持續將新的變動同時寫到內存和原來的 AOF 里。

  • 主進程獲取子進程重寫 AOF 的完成信號,往新 AOF 同步增量變動。

  • 使用新的 AOF 文件替換掉舊的 AOF 文件。

AOF 和 RDB 的優缺點

AOF 和 RDB 的優缺點如下:

  • RDB 優點:全量數據快照,文件小,恢復快。

  • RDB 缺點:無法保存最近一次快照之后的數據。

  • AOF 優點:可讀性高,適合保存增量數據,數據不易丟失。

  • AOF 缺點:文件體積大,恢復時間長。

RDB-AOF 混合持久化方式

Redis 4.0 之后推出了此種持久化方式,RDB 作為全量備份,AOF 作為增量備份,并且將此種方式作為默認方式使用。

在上述兩種方式中,RDB 方式是將全量數據寫入 RDB 文件,這樣寫入的特點是文件小,恢復快,但無法保存最近一次快照之后的數據,AOF 則將 Redis 指令存入文件中,這樣又會造成文件體積大,恢復時間長等弱點。

在 RDB-AOF 方式下,持久化策略首先將緩存中數據以 RDB 方式全量寫入文件,再將寫入后新增的數據以 AOF 的方式追加在 RDB 數據的后面,在下一次做 RDB 持久化的時候將 AOF 的數據重新以 RDB 的形式寫入文件。

這種方式既可以提高讀寫和恢復效率,也可以減少文件大小,同時可以保證數據的完整性。

在此種策略的持久化過程中,子進程會通過管道從父進程讀取增量數據,在以 RDB 格式保存全量數據時,也會通過管道讀取數據,同時不會造成管道阻塞。

可以說,在此種方式下的持久化文件,前半段是 RDB 格式的全量數據,后半段是 AOF 格式的增量數據。此種方式是目前較為推薦的一種持久化方式。

Redis 數據的恢復

RDB 和 AOF 文件共存情況下的恢復流程如下圖:

Redis入門必備指南


從圖可知,Redis 啟動時會先檢查 AOF 是否存在,如果 AOF 存在則直接加載 AOF,如果不存在 AOF,則直接加載 RDB 文件。

Pineline

Pipeline 和 Linux 的管道類似,它可以讓 Redis 批量執行指令。

Redis 基于請求/響應模型,單個請求處理需要一一應答。如果需要同時執行大量命令,則每條命令都需要等待上一條命令執行完畢后才能繼續執行,這中間不僅僅多了 RTT,還多次使用了系統 IO。

Pipeline 由于可以批量執行指令,所以可以節省多次 IO 和請求響應往返的時間。但是如果指令之間存在依賴關系,則建議分批發送指令。

Redis 的同步機制

主從同步原理

Redis 一般是使用一個 Master 節點來進行寫操作,而若干個 Slave 節點進行讀操作,Master 和 Slave 分別代表了一個個不同的 Redis Server 實例。

另外定期的數據備份操作也是單獨選擇一個 Slave 去完成,這樣可以最大程度發揮 Redis 的性能,為的是保證數據的弱一致性和最終一致性。

另外,Master 和 Slave 的數據不是一定要即時同步的,但是在一段時間后 Master 和 Slave 的數據是趨于同步的,這就是最終一致性。

Redis入門必備指南


全同步過程如下:

  • Slave 發送 Sync 命令到 Master。

  • Master 啟動一個后臺進程,將 Redis 中的數據快照保存到文件中。

  • Master 將保存數據快照期間接收到的寫命令緩存起來。

  • Master 完成寫文件操作后,將該文件發送給 Slave。

  • 使用新的 AOF 文件替換掉舊的 AOF 文件。

  • Master 將這期間收集的增量寫命令發送給 Slave 端。

增量同步過程如下:

  • Master 接收到用戶的操作指令,判斷是否需要傳播到 Slave。

  • 將操作記錄追加到 AOF 文件。

  • 將操作傳播到其他 Slave:對齊主從庫;往響應緩存寫入指令。

  • 將緩存中的數據發送給 Slave。

Redis Sentinel(哨兵)

主從模式弊端:當 Master 宕機后,Redis 集群將不能對外提供寫入操作。Redis Sentinel 可解決這一問題。

解決主從同步 Master 宕機后的主從切換問題:

  • 監控:檢查主從服務器是否運行正常。

  • 提醒:通過 API 向管理員或者其它應用程序發送故障通知。

  • 自動故障遷移:主從切換(在 Master 宕機后,將其中一個 Slave 轉為 Master,其他的 Slave 從該節點同步數據)。

Redis 集群

如何從海量數據里快速找到所需?

①分片

按照某種規則去劃分數據,分散存儲在多個節點上。通過將數據分到多個 Redis 服務器上,來減輕單個 Redis 服務器的壓力。

②一致性 Hash 算法

既然要將數據進行分片,那么通常的做法就是獲取節點的 Hash 值,然后根據節點數求模。

但這樣的方法有明顯的弊端,當 Redis 節點數需要動態增加或減少的時候,會造成大量的 Key 無法被命中。所以 Redis 中引入了一致性 Hash 算法。

該算法對 2^32 取模,將 Hash 值空間組成虛擬的圓環,整個圓環按順時針方向組織,每個節點依次為 0、1、2…2^32-1。

之后將每個服務器進行 Hash 運算,確定服務器在這個 Hash 環上的地址,確定了服務器地址后,對數據使用同樣的 Hash 算法,將數據定位到特定的 Redis 服務器上。

如果定位到的地方沒有 Redis 服務器實例,則繼續順時針尋找,找到的第一臺服務器即該數據最終的服務器位置。

Redis入門必備指南


③Hash 環的數據傾斜問題

Hash 環在服務器節點很少的時候,容易遇到服務器節點不均勻的問題,這會造成數據傾斜,數據傾斜指的是被緩存的對象大部分集中在 Redis 集群的其中一臺或幾臺服務器上。

Redis入門必備指南


如上圖,一致性 Hash 算法運算后的數據大部分被存放在 A 節點上,而 B 節點只存放了少量的數據,久而久之 A 節點將被撐爆。

針對這一問題,可以引入虛擬節點解決。簡單地說,就是為每一個服務器節點計算多個 Hash,每個計算結果位置都放置一個此服務器節點,稱為虛擬節點,可以在服務器 IP 或者主機名后放置一個編號實現。

Redis入門必備指南


例如上圖:將 NodeA 和 NodeB 兩個節點分為 Node A#1-A#3,NodeB#1-B#3。

讀者福利

加微信:haolagui521備注51CTO領取附送學習進階架構資料、PDF書籍文檔、面試資料

Redis入門必備指南

Redis入門必備指南


Redis入門必備指南Redis入門必備指南

以上就是Redis實用干貨分享的詳細內容了,看完之后是否Redis有新的認識呢?如果想了解更多相關內容,歡迎關注億速云行業資訊!


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

紫云| 博兴县| 崇左市| 莆田市| 昭觉县| 仁寿县| 福州市| 交口县| 英德市| 孟村| 锦屏县| 龙川县| 金华市| 徐闻县| 河西区| 沁源县| 宜都市| 凤山县| 瓮安县| 平乡县| 深州市| 尚志市| 静安区| 怀集县| 和平县| 虞城县| 铜川市| 浦县| 灵璧县| 翁牛特旗| 子长县| 安溪县| 禄劝| 东莞市| 柳林县| 永登县| 区。| 浙江省| 乌什县| 婺源县| 华阴市|