【RedisCluster】redis-cluster原理概述(虛擬槽+move/ask+cluster集群故障發現/恢復)


參考轉載於:https://www.cnblogs.com/williamjie/p/11132211.html

點個贊 很全面

 虛擬槽分區

虛擬槽分區是Redis Cluster采用的分區方式

預設虛擬槽,每個槽就相當於一個數字,有一定范圍。每個槽映射一個數據子集,一般比節點數大

步驟:

1.把16384槽按照節點數量進行平均分配,由節點進行管理
2.對每個key按照CRC16規則進行hash運算 3.把hash結果對16383進行取余 4.把余數發送給Redis節點 5.節點接收到數據,驗證是否在自己管理的槽編號的范圍 如果在自己管理的槽編號范圍內,則把數據保存到數據槽中,然后返回執行結果 如果在自己管理的槽編號范圍外,則會把數據發送給正確的節點,由正確的節點來把數據保存在對應的槽中
需要注意的是:Redis Cluster的節點之間會共享消息,每個節點都會知道是哪個節點負責哪個范圍內的數據槽

虛擬槽分布方式中,由於每個節點管理一部分數據槽,數據保存到數據槽中。當節點擴容或者縮容時,對數據槽進行重新分配遷移即可,數據不會丟失。
虛擬槽分區特點:

使用服務端管理節點,槽,數據:例如Redis Cluster
可以對數據打散,又可以保證數據分布均勻

 客戶端路由

moved重定向
1.每個節點通過通信都會共享Redis Cluster中槽和集群中對應節點的關系
2.客戶端向Redis Cluster的任意節點發送命令,接收命令的節點會根據CRC16規則進行hash運算與16383取余,計算自己的槽和對應節點 3.如果保存數據的槽被分配給當前節點,則去槽中執行命令,並把命令執行結果返回給客戶端 4.如果保存數據的槽不在當前節點的管理范圍內,則向客戶端返回moved重定向異常 5.客戶端接收到節點返回的結果,如果是moved異常,則從moved異常中獲取目標節點的信息 6.客戶端向目標節點發送命令,獲取命令執行結果
ask重定向

在對集群進行擴容和縮容時,需要對槽及槽中數據進行遷移

當客戶端向某個節點發送命令,節點向客戶端返回moved異常,告訴客戶端數據對應的槽的節點信息

如果此時正在進行集群擴展或者縮空操作,當客戶端向正確的節點發送命令時,槽及槽中數據已經被遷移到別的節點了,就會返回ask,這就是ask重定向機制

1.客戶端向目標節點發送命令,目標節點中的槽已經遷移支別的節點上了,此時目標節點會返回ask轉向給客戶端 2.客戶端向新的節點發送Asking命令給新的節點,然后再次向新節點發送命令 3.新節點執行命令,把命令執行結果返回給客戶端

moved異常與ask異常的相同點和不同點:

兩者都是客戶端重定向
moved異常:槽已經確定遷移,即槽已經不在當前節點 ask異常:槽還在遷移中

smart智能客戶端

使用智能客戶端的首要目標:追求性能

從集群中選一個可運行節點,使用Cluster slots初始化槽和節點映射

將Cluster slots的結果映射在本地,為每個節點創建JedisPool,相當於為每個redis節點都設置一個JedisPool,然后就可以進行數據讀寫操作

讀寫數據時的注意事項:

每個JedisPool中緩存了slot和節點node的關系
key和slot的關系:對key進行CRC16規則進行hash后與16383取余得到的結果就是槽 JedisCluster啟動時,已經知道key,slot和node之間的關系,可以找到目標節點 JedisCluster對目標節點發送命令,目標節點直接響應給JedisCluster 如果JedisCluster與目標節點連接出錯,則JedisCluster會知道連接的節點是一個錯誤的節點 此時JedisCluster會隨機節點發送命令,隨機節點返回moved異常給JedisCluster JedisCluster會重新初始化slot與node節點的緩存關系,然后向新的目標節點發送命令,目標命令執行命令並向JedisCluster響應 如果命令發送次數超過5次,則拋出異常"Too many cluster redirection!"

多節點命令實現

1.串行mget

定義for循環,遍歷所有的key,分別去所有的Redis節點中獲取值並進行匯總,簡單,但是效率不高,需要n次網絡時間

2.串行IO

對串行mget進行優化,在客戶端本地做內聚,對每個key進行CRC16hash,然后與16383取余,就可以知道哪個key對應的是哪個槽

本地已經緩存了槽與節點的對應關系,然后對key按節點進行分組,成立子集,然后使用pipeline把命令發送到對應的node,需要nodes次網絡時間,大大減少了網絡時間開銷

3.並行IO

並行IO是對串行IO的一個優化,把key分組之后,根據節點數量啟動對應的線程數,根據多線程模式並行向node節點請求數據,只需要1次網絡時間

4.hash_tag

將key進行hash_tag的包裝,然后把tag用大括號括起來,保證所有的key只向一個node請求數據,這樣執行類似mget命令只需要去一個節點獲取數據即可,效率更高

故障發現

Redis Cluster通過ping/pong消息實現故障發現:不需要sentinel

ping/pong不僅能傳遞節點與槽的對應消息,也能傳遞其他狀態,比如:節點主從狀態,節點故障等

故障發現就是通過這種模式來實現,分為主觀下線和客觀下線

主觀下線

某個節點認為另一個節點不可用,'偏見',只代表一個節點對另一個節點的判斷,不代表所有節點的認知

主觀下線流程:

1.節點1定期發送ping消息給節點2 2.如果發送成功,代表節點2正常運行,節點2會響應PONG消息給節點1,節點1更新與節點2的最后通信時間 3.如果發送失敗,則節點1與節點2之間的通信異常判斷連接,在下一個定時任務周期時,仍然會與節點2發送ping消息 4.如果節點1發現與節點2最后通信時間超過node-timeout,則把節點2標識為pfail狀態

 客觀下線

當半數以上持有槽的主節點都標記某節點主觀下線時,可以保證判斷的公平性

集群模式下,只有主節點(master)才有讀寫權限和集群槽的維護權限,從節點(slave)只有復制的權限

客觀下線流程:

1.某個節點接收到其他節點發送的ping消息,如果接收到的ping消息中包含了其他pfail節點,這個節點會將主觀下線的消息內容添加到自身的故障列表中,故障列表中包含了當前節點接收到的每一個節點對其他節點的狀態信息 2.當前節點把主觀下線的消息內容添加到自身的故障列表之后,會嘗試對故障節點進行客觀下線操作

故障列表的周期為:集群的node-timeout * 2,保證以前的故障消息不會對周期內的故障消息造成影響,保證客觀下線的公平性和有效性
 

故障恢復

資格檢查

對從節點的資格進行檢查,只有難過檢查的從節點才可以開始進行故障恢復
每個從節點檢查與故障主節點的斷線時間
超過cluster-node-timeout * cluster-slave-validity-factor數字,則取消資格 cluster-node-timeout默認為15秒,cluster-slave-validity-factor默認值為10 如果這兩個參數都使用默認值,則每個節點都檢查與故障主節點的斷線時間,如果超過150秒,則這個節點就沒有成為替換主節點的可能性

准備選舉時間

使偏移量最大的從節點具備優先級成為主節點的條件

選舉投票

對選舉出來的多個從節點進行投票,選出新的主節點

 替換主節點

當前從節點取消復制變成離節點(slaveof no one)
執行cluster del slot撤銷故障主節點負責的槽,並執行cluster add slot把這些槽分配給自己 向集群廣播自己的pong消息,表明已經替換了故障從節點

Redis Cluster的缺點

當節點數量很多時,性能不會很高
解決方式:使用智能客戶端。智能客戶端知道由哪個節點負責管理哪個槽,而且當節點與槽的映射關系發生改變時,客戶端也會知道這個改變,這是一種非常高效的方式
 
key批量操作支持有限:例如mget,mset必須在一個slot key事務和Lua支持有限:操作的key必須在一個節點 key是數據分區的最小粒度:不支持bigkey分區 不支持多個數據庫:集群模式下只有一個db0 復制只支持一層:不支持樹形復制結構 Redis Cluster滿足容量和性能的擴展性,很多業務'不需要' 大多數時客戶端性能會'降低' 命令無法跨節點使用:mget,keys,scan,flush,sinter等 Lua和事務無法跨節點使用 客戶端維護更復雜:SDK和應用本身消耗(例如更多的連接池)

很多場景Redis Sentinel已經夠用了

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM