Redis架构及分片管理
Redis 集群的 TCP 端口(Redis Cluster TCP ports)
?
每個(gè) Redis 集群節(jié)點(diǎn)需要兩個(gè) TCP 連接打開。正常的 TCP 端口用來服務(wù)客戶端,例如 6379,加 10000 的端口用作數(shù)據(jù)端口,在上面的例子中就是 16379。 第二個(gè)大一些的端口用于集群總線(bus),也就是使用二進(jìn)制協(xié)議的點(diǎn)到點(diǎn)通信通道。集群總線被節(jié)點(diǎn)用 于錯(cuò)誤檢測(cè),配置更新,故障轉(zhuǎn)移授權(quán)等等。客戶端不應(yīng)該嘗試連接集群總線端口,而應(yīng)一直與正常的 Redis 命令端口通信,但是要確保在防火墻中打開了這兩個(gè)端口,否則 Redis 集群的節(jié)點(diǎn)不能相互通信。 命令端口和集群總線端口的偏移量一直固定為 10000。 注意,為了讓 Redis 集群工作正常,對(duì)每個(gè)節(jié)點(diǎn): 1. 用于與客戶端通信的正常的客戶端通信端口(通常為 6379)需要開放給所有需要連接集群的客戶端 以及其他集群節(jié)點(diǎn)(使用客戶端端口來進(jìn)行鍵遷移)。 2. 集群總線端口(客戶端端口加 10000)必須從所有的其他集群節(jié)點(diǎn)可達(dá)。 如果你不打開這兩個(gè) TCP 端口,集群就無法正常工作。
?
Redis 集群的數(shù)據(jù)分片(Redis Cluster data sharding)
?
Redis 集群沒有使用一致性哈希,而是另外一種不同的分片形式,每個(gè)鍵概念上是被我們稱為哈希槽 (hash slot)的東西的一部分。 Redis 集群有 16384 個(gè)哈希槽,我們只是使用鍵的 CRC16 編碼對(duì) 16384 取模來計(jì)算一個(gè)指定鍵所屬的 哈希槽。 每一個(gè) Redis 集群中的節(jié)點(diǎn)都承擔(dān)一個(gè)哈希槽的子集,例如,你可能有一個(gè) 3 個(gè)節(jié)點(diǎn)的集群,其中:?
?? 節(jié)點(diǎn) A 包含從 0 到 5500 的哈希槽。
?? 節(jié)點(diǎn) B 包含從 5501 到 11000 的哈希槽。
?? 節(jié)點(diǎn) C 包含從 11001 到 16384 的哈希槽。
這可以讓在集群中添加和移除節(jié)點(diǎn)非常容易。例如,如果我想添加一個(gè)新節(jié)點(diǎn) D,我需要從節(jié)點(diǎn) A,B, C 移動(dòng)一些哈希槽到節(jié)點(diǎn) D。同樣地,如果我想從集群中移除節(jié)點(diǎn) A,我只需要移動(dòng) A 的哈希槽到 B 和 C。 當(dāng)節(jié)點(diǎn) A 變成空的以后,我就可以從集群中徹底刪除它。 因?yàn)閺囊粋€(gè)節(jié)點(diǎn)向另一個(gè)節(jié)點(diǎn)移動(dòng)哈希槽并不需要停止操作,所以添加和移除節(jié)點(diǎn),或者改變節(jié)點(diǎn)持有 的哈希槽百分比,都不需要任何停機(jī)時(shí)間(downtime)。
?
?
Redis cluster 架構(gòu)(Redis Cluster Architecture)
?? redis-cluster 架構(gòu)圖
?架構(gòu)細(xì)節(jié):
? ? 所有的 redis 節(jié)點(diǎn)彼此互聯(lián)(PING-PONG 機(jī)制),內(nèi)部使用二進(jìn)制協(xié)議優(yōu)化傳輸速度和帶寬.
? ? 節(jié)點(diǎn)的 fail 是通過集群中超過半數(shù)的節(jié)點(diǎn)檢測(cè)失效時(shí)才生效.
? ? 客戶端與 redis 節(jié)點(diǎn)直連,不需要中間 proxy 層.客戶端不需要連接集群所有節(jié)點(diǎn),連接集群中任何一個(gè) 可用節(jié)點(diǎn)即可
? ? redis-cluster 把所有的物理節(jié)點(diǎn)映射到[0-16383]slot 上,cluster 負(fù)責(zé)維護(hù) node<->slot<->value?
?
redis-cluster 選舉:容錯(cuò)
?? 領(lǐng)袖選舉過程是集群中所有 master 參與,如果半數(shù)以上 master 節(jié)點(diǎn)與 master 節(jié)點(diǎn)通信超過 (cluster-node-timeout),認(rèn)為當(dāng)前 master 節(jié)點(diǎn)掛掉.
?? 什么時(shí)候整個(gè)集群不可用(cluster_state:fail)
a:如果集群任意 master 掛掉,且當(dāng)前 master 沒有 slave.集群進(jìn)入 fail 狀態(tài),也可以理解成集群的 slot 映 射[0-16383]不完成時(shí)進(jìn)入 fail 狀態(tài). ps : redis-3.0.0.rc1 加入 cluster-require-full-coverage 參數(shù),默認(rèn)關(guān)閉, 打開集群兼容部分失敗.
b:如果集群超過半數(shù)以上 master 掛掉,無論是否有 slave 集群進(jìn)入 fail 狀態(tài).
?
ps:當(dāng)集群不可用時(shí),所有對(duì)集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down) 錯(cuò)誤
?
Redis 集群的主從模型(Redis Cluster master-slave model)
?
為了當(dāng)部分節(jié)點(diǎn)失效時(shí),或者無法與大多數(shù)節(jié)點(diǎn)通信時(shí)仍能保持可用,Redis 集群采用每個(gè)節(jié)點(diǎn)擁有 1(主 服務(wù)自身)到 N 個(gè)副本(N-1 個(gè)附加的從服務(wù)器)的主從模型。 在我們的例子中,集群擁有 A,B,C 三個(gè)節(jié)點(diǎn),如果節(jié)點(diǎn) B 失效集群將不能繼續(xù)服務(wù),因?yàn)槲覀儾辉?有辦法來服務(wù)在 5501-11000 范圍內(nèi)的哈希槽。 但是,如果當(dāng)我們創(chuàng)建集群后(或者稍后),我們?yōu)槊恳粋€(gè)主服務(wù)器添加一個(gè)從服務(wù)器,這樣最終的集群 就由主服務(wù)器 A,B,C 和從服務(wù)器 A1,B1,C1 組成,如果 B 節(jié)點(diǎn)失效系統(tǒng)仍能繼續(xù)服務(wù)。 B1 節(jié)點(diǎn)復(fù)制 B 節(jié)點(diǎn),于是集群會(huì)選舉 B1 節(jié)點(diǎn)作為新的主服務(wù)器,并繼續(xù)正確的運(yùn)轉(zhuǎn)。
?
?
Redis 集群的一致性保證(Redis Cluster consistency guarantees)
?
Redis 集群不保證強(qiáng)一致性。實(shí)踐中,這意味著在特定的條件下,Redis 集群可能會(huì)丟掉一些被系統(tǒng)收 到的寫入請(qǐng)求命令。
Redis 集群為什么會(huì)丟失寫請(qǐng)求的第一個(gè)原因,是因?yàn)椴捎昧水惒綇?fù)制。這意味著在寫期間下面的事情 發(fā)生了:
?? 你的客戶端向主服務(wù)器 B 寫入。
?? 主服務(wù)器 B 回復(fù) OK 給你的客戶端。
?? 主服務(wù)器 B 傳播寫入操作到其從服務(wù)器 B1,B2 和 B3。
?
?
手動(dòng)故障轉(zhuǎn)移(Manual failover)?
?
有時(shí)候在主服務(wù)器事實(shí)上沒有任何故障的情況下強(qiáng)制一次故障轉(zhuǎn)移是很有用的。例如,為了升級(jí)主服務(wù) 器節(jié)點(diǎn)中的一個(gè)進(jìn)程,可以對(duì)其進(jìn)行故障轉(zhuǎn)移使其變?yōu)橐粋€(gè)從服務(wù)器,這樣最小化了對(duì)可用性的影響。
Redis 集群支持使用 CLUSTER FAILOVER 命令來手動(dòng)故障轉(zhuǎn)移,必須在你想進(jìn)行故障轉(zhuǎn)移的主服務(wù)的 其中一個(gè)從服務(wù)器上執(zhí)行。
手動(dòng)故障轉(zhuǎn)移很特別,和真正因?yàn)橹鞣?wù)器失效而產(chǎn)生的故障轉(zhuǎn)移要更安全,因?yàn)椴扇×吮苊膺^程中數(shù) 據(jù)丟失的方式,僅當(dāng)系統(tǒng)確認(rèn)新的主服務(wù)器處理完了舊的主服務(wù)器的復(fù)制流時(shí),客戶端才從原主服務(wù)器切 換到新主服務(wù)器。?
?
創(chuàng)建redis集群(create a new cluser)?
redis-trib create --replicas 1 127.0.0.1:6379 127.0.0.1:7379 127.0.0.2:6379 127.0.0.2:7379 127.0.0.3:6379 127.0.0.3:7379 127.0.0.4:6379 127.0.0.4:7379 127.0.0.5:6379 127.0.0.5:7379
?
?查看redis集群狀態(tài)(check cluser status)?
redis-trib check 127.0.0.1:7379?
?
?查看node狀態(tài)(check?node?status)?
#? redis-cli -c -p 6379
#? INFO
?
添加新節(jié)點(diǎn)(Adding a new node)?
添加一個(gè)新節(jié)點(diǎn)的過程基本上就是,添加一個(gè)空節(jié)點(diǎn),然后,如果是作為主節(jié)點(diǎn)則移動(dòng)一些數(shù)據(jù)進(jìn)去, 如果是從節(jié)點(diǎn)則其作為某個(gè)節(jié)點(diǎn)的副本。
兩種情況我們都會(huì)討論,先從添加一個(gè)新的主服務(wù)器實(shí)例開始。
兩種情況下,第一步要完成的都是添加一個(gè)空節(jié)點(diǎn)。
我們使用與其他節(jié)點(diǎn)相同的配置(端口號(hào)除外)在 7006 端口(我們已存在的 6 個(gè)節(jié)點(diǎn)已經(jīng)使用了從 7000 到 7005 的端口)上開啟一個(gè)新的節(jié)點(diǎn),那么為了與我們之前的節(jié)點(diǎn)布局一致,你得這么做:?
? 在你的終端程序中開啟一個(gè)新的標(biāo)簽窗口。
? 進(jìn)入 cluster-test 目錄。
? 創(chuàng)建一個(gè)名為 7006 的目錄。
? 在里面創(chuàng)建一個(gè) redis.conf 的文件,類似于其它節(jié)點(diǎn)使用的文件,但是使用 7006 作為端口號(hào)。
? 最后使用../redis-server ./redis.conf 啟動(dòng)服務(wù)器。?
Java代碼??
?
添加副本節(jié)點(diǎn)(Adding a new node as a replica)
?
添加一個(gè)新副本可以有兩種方式。顯而易見的一種方式是再次使用 redis-trib,但是要使用—slave 選項(xiàng), 像這樣:
Java代碼??
?注意,這里的命令行完全像我們?cè)谔砑右粋€(gè)新主服務(wù)器時(shí)使用的一樣,所以我們沒有指定要給哪個(gè)主服 務(wù)器添加副本。這種情況下,redis-trib 會(huì)添加一個(gè)新節(jié)點(diǎn)作為一個(gè)具有較少副本的隨機(jī)的主服務(wù)器的副本。
但是,你可以使用下面的命令行精確地指定你想要的主服務(wù)器作為副本的目標(biāo):
?
Java代碼??
?
移除節(jié)點(diǎn)(Removing a node)
?
要移除一個(gè)從服務(wù)器節(jié)點(diǎn),只要使用 redis-trib 的 del-node 命令就可以:
Java代碼??
??
升級(jí)節(jié)點(diǎn)(Upgrading nodes in a Redis Cluster)?
?
升級(jí)從服務(wù)器節(jié)點(diǎn)很簡(jiǎn)單,因?yàn)槟阒恍枰V构?jié)點(diǎn)然后用已更新的 Redis 版本重啟。如果有客戶端使用 從服務(wù)器節(jié)點(diǎn)分離讀請(qǐng)求,它們應(yīng)該能夠在某個(gè)節(jié)點(diǎn)不可用時(shí)重新連接另一個(gè)從服務(wù)器。
升級(jí)主服務(wù)器要稍微復(fù)雜一些,建議的步驟是:?
?
1. 使用 CLUSTER FAILOVER 來觸發(fā)一次手工故障轉(zhuǎn)移主服務(wù)器(請(qǐng)看本文檔的手工故障轉(zhuǎn)移小 節(jié))。
2. 等待主服務(wù)器變?yōu)閺姆?wù)器。
3. 像升級(jí)從服務(wù)器那樣升級(jí)這個(gè)節(jié)點(diǎn)。
4. 如果你想讓你剛剛升級(jí)的節(jié)點(diǎn)成為主服務(wù)器,觸發(fā)一次新的手工故障轉(zhuǎn)移,讓升級(jí)的節(jié)點(diǎn)重新變 回主服務(wù)器。
總結(jié)
以上是生活随笔為你收集整理的Redis架构及分片管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis 哈希槽
- 下一篇: linux cmake编译源码,linu