Redis 為什么響應(yīng)快
1. 數(shù)據(jù)保存在內(nèi)存中
Redis 數(shù)據(jù)保存在內(nèi)存中,讀寫操作只要訪問內(nèi)存,不需要磁盤 IO。
2. 底層數(shù)據(jù)結(jié)構(gòu)
如下:
Redis 的數(shù)據(jù)以 key:value 的格式存儲在散列表中,時間復(fù)雜度 o(1)。
Redis 為 value 定義了豐富的數(shù)據(jù)結(jié)構(gòu),包括動態(tài)字符串、雙向鏈表、壓縮列表、hash、跳表和整數(shù)數(shù)組,可以根據(jù) value 的特性選擇選擇最高效的數(shù)據(jù)結(jié)構(gòu)。
3. 單線程模型
Redis 的網(wǎng)絡(luò) IO 和數(shù)據(jù)讀寫使用單線程模型,可以綁定 CPU,這避免了線程上下文切換帶來的開銷。
注意:Redis 6.0 對網(wǎng)絡(luò)請求引入了多線程模型,讀寫操作還是用單線程。
Redis 底層數(shù)據(jù)結(jié)構(gòu)
Redis 有 5 種數(shù)據(jù)類型,包括:字符串、列表、集合、有序集合和字典。
Redis 底層的數(shù)據(jù)結(jié)構(gòu)有 6 種,包括:動態(tài)字符串、雙向鏈表、壓縮列表(ziplist)、hash 表、跳表(skip list)和整數(shù)數(shù)組。
1. 字符串類型
底層數(shù)據(jù)結(jié)構(gòu)是動態(tài)字符串。
2. 列表
如果同時滿足下面條件,就使用壓縮列表,否則使用雙向鏈表:
列表中單個元素小于 64 字節(jié)
列表中元素個數(shù)少于 512
壓縮列表在內(nèi)存中是一塊兒連續(xù)的內(nèi)存空間,
壓縮列表查找時間復(fù)雜度是 o(n)。
3. 集合
如果同時滿足下面條件,就使用有序整數(shù)數(shù)組,否則使用 hash 表:
集合中元素都是整數(shù)類型
集合中元素個數(shù)不超過 512 個
4. 有序集合
如果同時滿足下面 2 個條件,就使用壓縮列表,否則使用跳表:
集合中元素都小于 64 字節(jié)
集合中元素個數(shù)小于 128 個
注意:有序集合還有一個 HASH 表用于保存集合中元素的分?jǐn)?shù),做 ZSCORE 操作時,查詢的就是這個 HASH 表,所以效率很高。如果不加索引,查找 10 這個數(shù)字需要查詢 10 次,使用了二級索引,查找 10 這個數(shù)字需要 5 次,而使用一級索引,需要查詢 3 次。跳表的每一層都是一個有序鏈表,最下面一層保存了全部數(shù)據(jù)。跳表插入、刪除、查詢的時間復(fù)雜度是 o(logN)。跳表需要存儲額外的索引節(jié)點(diǎn),會增加額外的空間開銷。
5. 字典
如果同時滿足下面 2 個條件,就使用壓縮列表,否則使用 hash 表:
字典中每個 entry 的 key/value 都小于 64 字節(jié)
字典中元素個數(shù)小于 512 個
Redis 緩存淘汰策略,Redis 總共有 8 種淘汰策略,如下圖:
volatile-lfu 和 allkeys-lfu 策略是 4.0 版本新增的:
lru:是按照數(shù)據(jù)的最近最少訪問原則來淘汰數(shù)據(jù),可能存在的問題是如果大批量冷數(shù)據(jù)最近被訪問了一次,就會占用大量內(nèi)存空間,如果緩存滿了,部分熱數(shù)據(jù)就會被淘汰掉。
lfu:是按照數(shù)據(jù)的最小訪問頻率訪問次數(shù)原則來淘汰數(shù)據(jù),如果兩個數(shù)據(jù)的訪問次數(shù)相同,則把訪問時間較早的數(shù)據(jù)淘汰。
Redis 數(shù)據(jù)持久化
Redis 持久化的方式有 2 種,一種是寫后日志(AOF),一種是內(nèi)存快照(RDB)。
1. AOF 日志
AOF 日志記錄了每一條收到的命令,Redis 故障宕機(jī)恢復(fù)時,可以加載 AOF 日志中的命令進(jìn)行重放來進(jìn)行故障恢復(fù)。
AOF 有 3 種同步策略:
Always:執(zhí)行命令同步寫盤;
everysec:每秒寫一次盤;
no:操作系統(tǒng)控制寫盤
如果不是對丟失數(shù)據(jù)特別敏感的業(yè)務(wù),推薦使用 everysec,對主線程的阻塞少,故障后丟失數(shù)據(jù)只有 1s。
2. RDB 快照
RDB 快照是一個內(nèi)存快照,記錄了 Redis 某一時刻的全部數(shù)據(jù)。
3. 混合日志
從 Redis 4.0 開始,AOF 文件也可以保存 RDB 快照,AOF 重寫的時候 Redis 會把 AOF 文件內(nèi)容清空,先記錄一份 RDB 快照,這份數(shù)據(jù)以"REDIS"開頭。
記錄 RDB 內(nèi)容后,AOF 文件會接著記錄 AOF 命令。故障恢復(fù)時,先加載 AOF 文件中 RDB 快照,然后回放 AOF 文件中后面的命令。
4. 主從同步
Redis 主從同步時,主節(jié)點(diǎn)會先生成一份 RDB 快照發(fā)送給從節(jié)點(diǎn),把快照之后的命令寫入主從同步緩存區(qū)(replication buffer),從節(jié)點(diǎn)把 RDB 文件加載完成后,主節(jié)點(diǎn)把緩存區(qū)命令發(fā)送給從節(jié)點(diǎn)。
5. AOF 重寫
AOF 日志是用記錄命令的方式追加的,這樣可能存在對同一個 key 的多條命令,這些命令是可以合并成 1 條的。比如對同一個 key 的多個 set 操作日志,可以合成一條。
6. 阻塞
AOF 重寫和 RDB 快照執(zhí)行的過程中,Redis 都會 Fork 一個子進(jìn)程來執(zhí)行操作,子進(jìn)程執(zhí)行過程中是不是阻塞主線程的。
但是要注意 2 點(diǎn):
Fork 子進(jìn)程的過程中,Redis 主線程會拷貝一份內(nèi)存頁表(記錄了虛擬內(nèi)存和物理內(nèi)存的映射關(guān)系)給子進(jìn)程,這個過程是阻塞的,Redis 主線程內(nèi)存越大,阻塞時間越長。
子進(jìn)程和 Redis 主線程共用一塊兒物理內(nèi)存,如果新的請求到來,必須使用 copy on write 的方式,拷貝要修改的數(shù)據(jù)頁到新的內(nèi)存空間進(jìn)行修改。
注意:如果開啟了內(nèi)存大頁,每次拷貝都需要分配 2MB 的內(nèi)存。
Redis 高可用
從圖我們可以看到哨兵之間、哨兵和主從節(jié)點(diǎn)之間、哨兵和客戶端之間都建立了連接。
如果主節(jié)點(diǎn)掛了,哨兵集群需要完成主從切換:判斷主節(jié)點(diǎn)下線--->選舉新主---->選舉哨兵leader---->執(zhí)行主從切換:
1. 判斷主節(jié)點(diǎn)下線
當(dāng)一個哨兵監(jiān)控到主節(jié)點(diǎn)下線時,就會給其他哨兵發(fā)送確認(rèn)命令,其他命令會根據(jù)自己的判斷回復(fù)"Y"或"N"。
如果有 n/2+1 以上數(shù)量的哨兵都認(rèn)為主節(jié)點(diǎn)下線了,才會判定主節(jié)點(diǎn)下線。這里的n是哨兵集群的數(shù)量。
n/2+1 這個參數(shù)由 quorum 參數(shù)配置,比如有 5 個哨兵,這里一般配置成 3。也可以配置成其他值。
2. 選舉新主節(jié)點(diǎn)
主節(jié)點(diǎn)被判定下線后,哨兵集群會重新選擇新的主節(jié)點(diǎn)。
淘汰不穩(wěn)定從節(jié)點(diǎn):根據(jù)配置參數(shù) down-after-milliseconds * 10 來淘汰。
down-after-milliseconds 表示主從節(jié)點(diǎn)斷開時間,10 表示次數(shù),如果從節(jié)點(diǎn)跟主節(jié)點(diǎn)斷開時間超過 down-after-milliseconds 的次數(shù)達(dá)到了 10 次以上,從節(jié)點(diǎn)就被淘汰了。
slave-priority 參數(shù):配置了從節(jié)點(diǎn)的優(yōu)先級,選擇從節(jié)點(diǎn)時哨兵會優(yōu)先選擇優(yōu)先級高的從節(jié)點(diǎn)。
復(fù)制進(jìn)度:Redis 有一個記錄主從增量復(fù)制的緩存區(qū)叫 repl_backlog_buffer。
主節(jié)點(diǎn)有一個寫偏移量 master_repl_offset,從節(jié)點(diǎn)也有一個偏移量 slave_repl_offset。
優(yōu)先選擇 slave_repl_offset 最接近 master_repl_offset 的從節(jié)點(diǎn)作為新的主節(jié)點(diǎn)。
所以,上圖中偏移量為 114 的從節(jié)點(diǎn)優(yōu)先被選為新的主節(jié)點(diǎn)。
ID 編號:優(yōu)先級和參數(shù)都一樣的情況下,ID 編號小的從節(jié)點(diǎn)優(yōu)先被選為新主節(jié)點(diǎn)。
3. 選舉哨兵 Leader
第一個判斷主節(jié)點(diǎn)下線的哨兵節(jié)點(diǎn)收到其他節(jié)點(diǎn)的回復(fù)并確定主節(jié)點(diǎn)下線后,就會給其他哨兵發(fā)送命令申請成為哨兵 Leader。
成為 Leader 的條件如下:
收到贊成票必須大于等 quorum 值
必須拿到半數(shù)以上的贊成票
如果集群配置了 5 個哨兵,quorum 的值設(shè)置為 3,其中一個哨兵節(jié)點(diǎn)掛了,很有可能會判斷到主節(jié)點(diǎn)下線,但是因為選舉不出哨兵 Leader 而不能切換。
如果集群有 2 個哨兵,其中一個掛了,那必定選不出哨兵 Leader。
4. 主節(jié)點(diǎn)切換
選出新主節(jié)點(diǎn)和哨兵 Leader 后,哨兵 Leader 會執(zhí)行主從切換的操作。
完成后會做一些事件通知:
通知其他哨兵新主節(jié)點(diǎn)地址
通知所有從節(jié)點(diǎn)新的主節(jié)點(diǎn)地址,從節(jié)點(diǎn)收到后向新主節(jié)點(diǎn)請求主從同步
通知客戶端連接新主節(jié)點(diǎn)
5. 主從切換過程中請求處理
如果客戶端的讀請求會發(fā)送到從節(jié)點(diǎn),可以正常處理。在客戶端收到新主節(jié)點(diǎn)地址通知前寫請求會失敗??蛻舳丝梢圆扇∫恍?yīng)急措施應(yīng)對主節(jié)點(diǎn)下線,比如緩存寫請求。
為了能夠及時獲取到新主節(jié)點(diǎn)信息,客戶端可以訂閱哨兵的主節(jié)點(diǎn)下線事件和新主節(jié)點(diǎn)變更事件。
Redis 實現(xiàn)分布式鎖
1. Redis 單節(jié)點(diǎn)的分布式鎖
一個服務(wù)部署了 2 個客戶端,獲取分布式鎖時一個成功,另一個就失敗了。
Redis 一般使用 setnx 實現(xiàn)分布式鎖,命令如下:
SETNX KEY_NAME VALUE
設(shè)置成功返回 1,設(shè)置失敗返回 0。使用單節(jié)點(diǎn)分布式鎖存在一些問題。
客戶端 1 獲取鎖后發(fā)生了故障:結(jié)果鎖就不能釋放了,其他客戶端永遠(yuǎn)獲取不到鎖。
解決方法是用下面命令對 key 設(shè)置過期時間:
SET key value [EX seconds] [PX milliseconds] NX
客戶端 2 誤刪除了鎖:解決方法是對 key 設(shè)置 value 時加入一個客戶端表示,比如在客戶端 1 設(shè)置 key 時在 value 前拼接一個字符串 application1,刪除的時候做一下判斷。
2. Redis 紅鎖
Redis 單節(jié)點(diǎn)會有可靠性問題,節(jié)點(diǎn)故障后鎖操作就會失敗。Redis 為了應(yīng)對單點(diǎn)故障的問題,設(shè)計了多節(jié)點(diǎn)的分布式鎖,也叫紅鎖。
主要思想是客戶端跟多個 Redis 實例請求加鎖,只有超過半數(shù)的實例加鎖成功,才認(rèn)為成功獲取了分布式鎖。
更多精彩干貨分享
點(diǎn)擊下方名片關(guān)注
IT那活兒
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/129777.html
摘要:哨兵是社區(qū)版本推出的原生高可用解決方案,部署架構(gòu)主要包括兩部分集群和數(shù)據(jù)集群,其中集群是由若干節(jié)點(diǎn)組成的分布式集群。自研推薦推薦自研的高可用解決方案,主要體現(xiàn)在配置中心故障探測和的處理機(jī)制上,通常需要根據(jù)企業(yè)業(yè)務(wù)的實際線上環(huán)境來定制化。 最近很多朋友向我咨詢關(guān)于高可用的方案的優(yōu)缺點(diǎn)以及如何選擇合適的方案線上使用,剛好最近在給宜人貸,光大銀行做企業(yè)內(nèi)訓(xùn)的時候也詳細(xì)講過,這里我再整理發(fā)出來...
摘要:哨兵是社區(qū)版本推出的原生高可用解決方案,部署架構(gòu)主要包括兩部分集群和數(shù)據(jù)集群,其中集群是由若干節(jié)點(diǎn)組成的分布式集群。自研推薦推薦自研的高可用解決方案,主要體現(xiàn)在配置中心故障探測和的處理機(jī)制上,通常需要根據(jù)企業(yè)業(yè)務(wù)的實際線上環(huán)境來定制化。 最近很多朋友向我咨詢關(guān)于高可用的方案的優(yōu)缺點(diǎn)以及如何選擇合適的方案線上使用,剛好最近在給宜人貸,光大銀行做企業(yè)內(nèi)訓(xùn)的時候也詳細(xì)講過,這里我再整理發(fā)出來...
摘要:而今天主要講用得比較多的三個。支持持久化操作,可以進(jìn)行及數(shù)據(jù)持久化到磁盤,從而進(jìn)行數(shù)據(jù)備份或數(shù)據(jù)恢復(fù)等操作,較好的防止數(shù)據(jù)丟失的手段。單線程請求,所有命令串行執(zhí)行,并發(fā)情況下不需要考慮數(shù)據(jù)一致性問題。 前言 NoSQL,泛指非關(guān)系型的數(shù)據(jù)庫。隨著互聯(lián)網(wǎng)不斷的發(fā)展,傳統(tǒng)的關(guān)系數(shù)據(jù)庫在應(yīng)付新互聯(lián)網(wǎng)模式的網(wǎng)站,特別是超大規(guī)模和高并發(fā)的SNS類型的純動態(tài)網(wǎng)站已經(jīng)顯得力不從心,暴露了很多難以克服...
摘要:而今天主要講用得比較多的三個。支持持久化操作,可以進(jìn)行及數(shù)據(jù)持久化到磁盤,從而進(jìn)行數(shù)據(jù)備份或數(shù)據(jù)恢復(fù)等操作,較好的防止數(shù)據(jù)丟失的手段。單線程請求,所有命令串行執(zhí)行,并發(fā)情況下不需要考慮數(shù)據(jù)一致性問題。 前言 NoSQL,泛指非關(guān)系型的數(shù)據(jù)庫。隨著互聯(lián)網(wǎng)不斷的發(fā)展,傳統(tǒng)的關(guān)系數(shù)據(jù)庫在應(yīng)付新互聯(lián)網(wǎng)模式的網(wǎng)站,特別是超大規(guī)模和高并發(fā)的SNS類型的純動態(tài)網(wǎng)站已經(jīng)顯得力不從心,暴露了很多難以克服...
摘要:而今天主要講用得比較多的三個。支持持久化操作,可以進(jìn)行及數(shù)據(jù)持久化到磁盤,從而進(jìn)行數(shù)據(jù)備份或數(shù)據(jù)恢復(fù)等操作,較好的防止數(shù)據(jù)丟失的手段。單線程請求,所有命令串行執(zhí)行,并發(fā)情況下不需要考慮數(shù)據(jù)一致性問題。 前言 NoSQL,泛指非關(guān)系型的數(shù)據(jù)庫。隨著互聯(lián)網(wǎng)不斷的發(fā)展,傳統(tǒng)的關(guān)系數(shù)據(jù)庫在應(yīng)付新互聯(lián)網(wǎng)模式的網(wǎng)站,特別是超大規(guī)模和高并發(fā)的SNS類型的純動態(tài)網(wǎng)站已經(jīng)顯得力不從心,暴露了很多難以克服...
閱讀 1356·2023-01-11 13:20
閱讀 1707·2023-01-11 13:20
閱讀 1215·2023-01-11 13:20
閱讀 1906·2023-01-11 13:20
閱讀 4165·2023-01-11 13:20
閱讀 2757·2023-01-11 13:20
閱讀 1402·2023-01-11 13:20
閱讀 3671·2023-01-11 13:20