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