Redis Cluster是Redis官方提供的Redis集群功能
1.為什么要實作Redis Cluster
1.主從復制不能實作高可用
2.隨著公司發展,用戶數量增多,并發越來越多,業務需要更高的QPS,而主從復制中單機的QPS可能無法滿足業務需求
3.資料量的考慮,現有服務器記憶體不能滿足業務資料的需要時,單純向服務器添加記憶體不能達到要求,此時需要考慮分布式需求,把資料分布到不同服務器上
4.網路流量需求:業務的流量已經超過服務器的網卡的上限值,可以考慮使用分布式來進行分流
5.離線計算,需要中間環節緩沖等別的需求,6.一家之言,不足之處還請斧正,歡迎各位老禿進群973961276交流生發植發經驗(手動狗頭)
2.資料分布
2.1 為什么要做資料分布
全量資料,單機Redis節點無法滿足要求,按照磁區規則把資料分到若干個子集當中

2.2 常用資料分布方式之順序分布
比如:1到100個數字,要保存在3個節點上,按照順序磁區,把資料平均分配三個節點上
1號到33號資料保存到節點1上,34號到66號資料保存到節點2上,67號到100號資料保存到節點3上

順序磁區常用在關系型資料庫的設計
2.3 常用資料分布方式之哈希分布
例如1到100個數字,對每個數字進行哈希運算,然后對每個數的哈希結果除以節點數進行取余,余數為1則保存在第1個節點上,余數為2則保存在第2個節點上,余數為0則保存在第3個節點,這樣可以保證資料被打散,同時保證資料分布的比較均勻

哈希分布方式分為三個磁區方式:
2.3.1 節點取余磁區
比如有100個資料,對每個資料進行hash運算之后,與節點數進行取余運算,根據余數不同保存在不同的節點上

節點取余方式是非常簡單的一種磁區方式
節點取余磁區方式有一個問題:即當增加或減少節點時,原來節點中的80%的資料會進行遷移操作,對所有資料重新進行分布
節點取余磁區方式建議使用多倍擴容的方式,例如以前用3個節點保存資料,擴容為比以前多一倍的節點即6個節點來保存資料,這樣只需要適移50%的資料,資料遷移之后,第一次無法從快取中讀取資料,必須先從資料庫中讀取資料,然后回寫到快取中,然后才能從快取中讀取遷移之后的資料

節點取余方式優點:
客戶端分片
配置簡單:對資料進行哈希,然后取余
節點取余方式缺點:
資料節點伸縮時,導致資料遷移
遷移數量和添加節點資料有關,建議翻倍擴容
2.3.2 一致性哈希磁區
一致性哈希原理:
將所有的資料當做一個token環,token環中的資料范圍是0到2的32次方,然后為每一個資料節點分配一個token范圍值,這個節點就負責保存這個范圍內的資料,

對每一個key進行hash運算,被哈希后的結果在哪個token的范圍內,則按順時針去找最近的節點,這個key將會被保存在這個節點上,


在上面的圖中,有4個key被hash之后的值在在n1節點和n2節點之間,按照順時針規則,這4個key都會被保存在n2節點上,
如果在n1節點和n2節點之間添加n5節點,當下次有key被hash之后的值在n1節點和n5節點之間,這些key就會被保存在n5節點上面了
在上面的例子里,添加n5節點之后,資料遷移會在n1節點和n2節點之間進行,n3節點和n4節點不受影響,資料遷移范圍被縮小很多
同理,如果有1000個節點,此時添加一個節點,受影響的節點范圍最多只有千分之2
一致性哈希一般用在節點比較多的時候
一致性哈希磁區優點:
采用客戶端分片方式:哈希 + 順時針(優化取余)
節點伸縮時,只影響鄰近節點,但是還是有資料遷移
一致性哈希磁區缺點:
翻倍伸縮,保證最小遷移資料和負載均衡
2.3.3 虛擬槽磁區
虛擬槽磁區是Redis Cluster采用的磁區方式
預設虛擬槽,每個槽就相當于一個數字,有一定范圍,每個槽映射一個資料子集,一般比節點數大
Redis Cluster中預設虛擬槽的范圍為0到16383

步驟:
1.把16384槽按照節點數量進行平均分配,由節點進行管理
2.對每個key按照CRC16規則進行hash運算
3.把hash結果對16383進行取余
4.把余數發送給Redis節點
5.節點接收到資料,驗證是否在自己管理的槽編號的范圍
如果在自己管理的槽編號范圍內,則把資料保存到資料槽中,然后回傳執行結果
如果在自己管理的槽編號范圍外,則會把資料發送給正確的節點,由正確的節點來把資料保存在對應的槽中
需要注意的是:Redis Cluster的節點之間會共享訊息,每個節點都會知道是哪個節點負責哪個范圍內的資料槽
虛擬槽分布方式中,由于每個節點管理一部分資料槽,資料保存到資料槽中,當節點擴容或者縮容時,對資料槽進行重新分配遷移即可,資料不會丟失,
虛擬槽磁區特點:
使用服務端管理節點,槽,資料:例如Redis Cluster
可以對資料打散,又可以保證資料分布均勻
2.3 順序分布與哈希分布的對比

3.Redis Cluster基本架構
3.1 節點
Redis Cluster是分布式架構:即Redis Cluster中有多個節點,每個節點都負責進行資料讀寫操作
每個節點之間會進行通信,
3.2 meet操作
節點之間會相互通信
meet操作是節點之間完成相互通信的基礎,meet操作有一定的頻率和規則

3.3 分配槽
把16384個槽平均分配給節點進行管理,每個節點只能對自己負責的槽進行讀寫操作
由于每個節點之間都彼此通信,每個節點都知道另外節點負責管理的槽范圍

客戶端訪問任意節點時,對資料key按照CRC16規則進行hash運算,然后對運算結果對16383進行取作,如果余數在當前訪問的節點管理的槽范圍內,則直接回傳對應的資料
如果不在當前節點負責管理的槽范圍內,則會告訴客戶端去哪個節點獲取資料,由客戶端去正確的節點獲取資料


3.4 復制
保證高可用,每個主節點都有一個從節點,當主節點故障,Cluster會按照規則實作主備的高可用性
對于節點來說,有一個配置項:cluster-enabled,即是否以集群模式啟動
3.5 客戶端路由
3.5.1 moved重定向
1.每個節點通過通信都會共享Redis Cluster中槽和集群中對應節點的關系
2.客戶端向Redis Cluster的任意節點發送命令,接收命令的節點會根據CRC16規則進行hash運算與16383取余,計算自己的槽和對應節點
3.如果保存資料的槽被分配給當前節點,則去槽中執行命令,并把命令執行結果回傳給客戶端
4.如果保存資料的槽不在當前節點的管理范圍內,則向客戶端回傳moved重定向例外
5.客戶端接收到節點回傳的結果,如果是moved例外,則從moved例外中獲取目標節點的資訊
6.客戶端向目標節點發送命令,獲取命令執行結果

需要注意的是:客戶端不會自動找到目標節點執行命令
槽命中:直接回傳

[root@mysql ~]# redis-cli -p 9002 cluster keyslot hello
(integer) 866
槽不命中:moved例外
[root@mysql ~]# redis-cli -p 9002 cluster keyslot php
(integer) 9244

[root@mysql ~]# redis-cli -c -p 9002
127.0.0.1:9002> cluster keyslot hello
(integer) 866
127.0.0.1:9002> set hello world
-> Redirected to slot [866] located at 192.168.81.100:9003
OK
192.168.81.100:9003> cluster keyslot python
(integer) 7252
192.168.81.100:9003> set python best
-> Redirected to slot [7252] located at 192.168.81.101:9002
OK
192.168.81.101:9002> get python
"best"
192.168.81.101:9002> get hello
-> Redirected to slot [866] located at 192.168.81.100:9003
"world"
192.168.81.100:9003> exit
[root@mysql ~]# redis-cli -p 9002
127.0.0.1:9002> cluster keyslot python
(integer) 7252
127.0.0.1:9002> set python best
OK
127.0.0.1:9002> set hello world
(error) MOVED 866 192.168.81.100:9003
127.0.0.1:9002> exit
[root@mysql ~]#
3.5.2 ask重定向

在對集群進行擴容和縮容時,需要對槽及槽中資料進行遷移
當客戶端向某個節點發送命令,節點向客戶端回傳moved例外,告訴客戶端資料對應的槽的節點資訊
如果此時正在進行集群擴展或者縮空操作,當客戶端向正確的節點發送命令時,槽及槽中資料已經被遷移到別的節點了,就會回傳ask,這就是ask重定向機制

步驟:
1.客戶端向目標節點發送命令,目標節點中的槽已經遷移支別的節點上了,此時目標節點會回傳ask轉向給客戶端
2.客戶端向新的節點發送Asking命令給新的節點,然后再次向新節點發送命令
3.新節點執行命令,把命令執行結果回傳給客戶端
moved例外與ask例外的相同點和不同點
兩者都是客戶端重定向
moved例外:槽已經確定遷移,即槽已經不在當前節點
ask例外:槽還在遷移中
3.5.3 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!"

3.6 多節點命令實作
Redis Cluster不支持使用scan命令掃描所有節點
多節點命令就是在在所有節點上都執行一條命令
批量操作優化
3.6.1 串行mget
定義for回圈,遍歷所有的key,分別去所有的Redis節點中獲取值并進行匯總,簡單,但是效率不高,需要n次網路時間

3.6.2 串行IO
對串行mget進行優化,在客戶端本地做內聚,對每個key進行CRC16hash,然后與16383取余,就可以知道哪個key對應的是哪個槽
本地已經快取了槽與節點的對應關系,然后對key按節點進行分組,成立子集,然后使用pipeline把命令發送到對應的node,需要nodes次網路時間,大大減少了網路時間開銷

3.6.3 并行IO
并行IO是對串行IO的一個優化,把key分組之后,根據節點數量啟動對應的執行緒數,根據多執行緒模式并行向node節點請求資料,只需要1次網路時間

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

3.6.5 四種優化方案優缺點分析

3.7 故障發現
Redis Cluster通過ping/pong訊息實作故障發現:不需要sentinel
ping/pong不僅能傳遞節點與槽的對應訊息,也能傳遞其他狀態,比如:節點主從狀態,節點故障等
故障發現就是通過這種模式來實作,分為主觀下線和客觀下線
3.7.1 主觀下線
某個節點認為另一個節點不可用,'偏見',只代表一個節點對另一個節點的判斷,不代表所有節點的認知
主觀下線流程:
1.節點1定期發送ping訊息給節點2
2.如果發送成功,代表節點2正常運行,節點2會回應PONG訊息給節點1,節點1更新與節點2的最后通信時間
3.如果發送失敗,則節點1與節點2之間的通信例外判斷連接,在下一個定時任務周期時,仍然會與節點2發送ping訊息
4.如果節點1發現與節點2最后通信時間超過node-timeout,則把節點2標識為pfail狀態

3.7.2 客觀下線
當半數以上持有槽的主節點都標記某節點主觀下線時,可以保證判斷的公平性
集群模式下,只有主節點(master)才有讀寫權限和集群槽的維護權限,從節點(slave)只有復制的權限
客觀下線流程:
1.某個節點接收到其他節點發送的ping訊息,如果接收到的ping訊息中包含了其他pfail節點,這個節點會將主觀下線的訊息內容添加到自身的故障串列中,故障串列中包含了當前節點接收到的每一個節點對其他節點的狀態資訊
2.當前節點把主觀下線的訊息內容添加到自身的故障串列之后,會嘗試對故障節點進行客觀下線操作
故障串列的周期為:集群的node-timeout * 2,保證以前的故障訊息不會對周期內的故障訊息造成影響,保證客觀下線的公平性和有效性


3.8 故障恢復
3.8.1 資格檢查
對從節點的資格進行檢查,只有難過檢查的從節點才可以開始進行故障恢復
每個從節點檢查與故障主節點的斷線時間
超過cluster-node-timeout * cluster-slave-validity-factor數字,則取消資格
cluster-node-timeout默認為15秒,cluster-slave-validity-factor默認值為10
如果這兩個引數都使用默認值,則每個節點都檢查與故障主節點的斷線時間,如果超過150秒,則這個節點就沒有成為替換主節點的可能性
3.9.2 準備選舉時間
使偏移量最大的從節點具備優先級成為主節點的條件

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

3.8.4 替換主節點
當前從節點取消復制變成離節點(slaveof no one)
執行cluster del slot撤銷故障主節點負責的槽,并執行cluster add slot把這些槽分配給自己
向集群廣播自己的pong訊息,表明已經替換了故障從節點
3.8.5 故障轉移演練
對某一個主節點執行kill -9 {pid}來模擬宕機的情況
3.9 Redis Cluster的缺點
當節點數量很多時,性能不會很高
解決方式:使用智能客戶端,智能客戶端知道由哪個節點負責管理哪個槽,而且當節點與槽的映射關系發生改變時,客戶端也會知道這個改變,這是一種非常高效的方式
4.搭建Redis Cluster
搭建Redis Cluster有兩種安裝方式
- 1.原生命令安裝
- 2.官方工具安裝
5.開發運維常見的問題
5.1 集群完整性
cluster-require-full-coverage默認為yes,即是否集群中的所有節點都是在線狀態且16384個槽都處于服務狀態時,集群才會提供服務
集群中16384個槽全部處于服務狀態,保證集群完整性
當某個節點故障或者正在故障轉移時獲取資料會提示:(error)CLUSTERDOWN The cluster is down
建議把cluster-require-full-coverage設定為no
5.2 帶寬消耗
Redis Cluster節點之間會定期交換Gossip訊息,以及做一些心跳檢測
官方建議Redis Cluster節點數量不要超過1000個,當集群中節點數量過多時,會產生不容忽視的帶寬消耗
訊息發送頻率:節點發現與其他節點最后通信時間超過cluster-node-timeout /2時,會直接發送PING訊息
訊息資料量:slots槽陣列(2kb空間)和整個集群1/10的狀態資料(10個節點狀態資料約為1kb)
節點部署的機器規模:集群分布的機器越多且每臺機器劃分的節點數越均勻,則集群內整體的可用帶寬越高
帶寬優化:
避免使用'大'集群:避免多業務使用一個集群,大業務可以多集群
cluster-node-timeout:帶寬和故障轉移速度的均衡
盡量均勻分配到多機器上:保證高可用和帶寬
5.3 Pub/Sub廣播
在任意一個cluster節點執行publish,則發布的訊息會在集群中傳播,集群中的其他節點都會訂閱到訊息,這樣節點的帶寬的開銷會很大
publish在集群每個節點廣播,加重帶寬
解決辦法:需要使用Pub/Sub時,為了保證高可用,可以單獨開啟一套Redis Sentinel
5.4 集群傾斜
對于分布式資料庫來說,存在傾斜問題是比較常見的
集群傾斜也就是各個節點使用的記憶體不一致
5.4.1 資料傾斜原因
1.節點和槽分配不均,如果使用redis-trib.rb工具構建集群,則出現這種情況的機會不多
redis-trib.rb info ip:port查看節點,槽,鍵值分布
redis-trib.rb rebalance ip:port進行均衡(謹慎使用)
2.不同槽對應鍵值數量差異比較大
CRC16算法正常情況下比較均勻
可能存在hash_tag
cluster countkeysinslot {slot}獲取槽對應鍵值個數
3.包含bigkey:例如大字串,幾百萬的元素的hash,set等
在從節點:redis-cli --bigkeys
優化:優化資料結構
4.記憶體相關配置不一致
hash-max-ziplist-value:滿足一定條件情況下,hash可以使用ziplist
set-max-intset-entries:滿足一定條件情況下,set可以使用intset
在一個集群內有若干個節點,當其中一些節點配置上面兩項優化,另外一部分節點沒有配置上面兩項優化
當集群中保存hash或者set時,就會造成節點資料不均勻
優化:定期檢查配置一致性
5.請求傾斜:熱點key
重要的key或者bigkey
Redis Cluster某個節點有一個非常重要的key,就會存在熱點問題
5.4.2 集群傾斜優化:
避免bigkey
熱鍵不要用hash_tag
當一致性不高時,可以用本地快取+ MQ(訊息佇列)
5.5 集群讀寫分離
只讀連接:集群模式下,從節點不接受任何讀寫請求
當向從節點執行讀請求時,重定向到負責槽的主節點
readonly命令可以讀:連接級別命令,當連接斷開之后,需要再次執行readonly命令
讀寫分離:
同樣的問題:復制延遲,讀取過期資料,從節點故障
修改客戶端:cluster slaves {nodeId}
5.6 資料遷移
官方遷移工具:redis-trib.rb和import
只能從單機遷移到集群
不支持在線遷移:source需要停寫
不支持斷點續傳
單執行緒遷移:影響深度
在線遷移:
唯品會:redis-migrate-tool
豌豆莢:redis-port
5.7 集群VS單機
集群的限制:
key批量操作支持有限:例如mget,mset必須在一個slot
key事務和Lua支持有限:操作的key必須在一個節點
key是資料磁區的最小粒度:不支持bigkey磁區
不支持多個資料庫:集群模式下只有一個db0
復制只支持一層:不支持樹形復制結構
Redis Cluster滿足容量和性能的擴展性,很多業務'不需要'
大多數時客戶端性能會'降低'
命令無法跨節點使用:mget,keys,scan,flush,sinter等
Lua和事務無法跨節點使用
客戶端維護更復雜:SDK和應用本身消耗(例如更多的連接池)
很多場景Redis Sentinel已經夠用了
6.Redis Cluster總結:
1.Redis Cluster資料磁區規則采用虛擬槽方式(16384個槽),每個節點負責一部分槽和相關資料,實作資料和請求的負載均衡
2.搭建Redis Cluster劃分四個步驟:準備節點,meet操作,分配槽,復制資料,
3.Redis官方推薦使用redis-trib.rb工具快速搭建Redis Cluster
4.集群伸縮通過在節點之間移動槽和相關資料實作
擴容時根據槽遷移計劃把槽從源節點遷移到新節點
收縮時如果下線的節點有負責的槽需要遷移到其他節點,再通過cluster forget命令讓集群內所有節點忘記被下線節點
5.使用smart客戶端操作集群過到通信效率最大化,客戶端內部負責計算維護鍵,槽以及節點的映射,用于快速定位到目標節點
6.集群自動故障轉移程序分為故障發現和節點恢復,節點下線分為主觀下線和客觀下線,當超過半數節點認為故障節點為主觀下線時,標記這個節點為客觀下線狀態,從節點負責對客觀下線的主節點觸發故障恢復流程,保證集群的可用性
7.開發運維常見問題包括:超大規模集群帶席消耗,pub/sub廣播問題,集群傾斜問題,單機和集群對比等
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/254098.html
標籤:其他
上一篇:談談Epoll是如何作業的?
下一篇:試題 演算法訓練 報數
