高可用Redis(十二):Redis Cluster

來源:互聯網
上載者:User

標籤:image   豌豆莢   維護   ast   儲存資料   導致   熱鍵   set   3.1   

Redis Cluster是Redis官方提供的Redis叢集功能

1.為什麼要實現Redis Cluster
1.主從複製不能實現高可用2.隨著公司發展,使用者數量增多,並發越來越多,業務需要更高的QPS,而主從複製中單機的QPS可能無法滿足業務需求3.資料量的考慮,現有伺服器記憶體不能滿足業務資料的需要時,單純向伺服器添加記憶體不能達到要求,此時需要考慮分布式需求,把資料分布到不同伺服器上4.網路流量需求:業務的流量已經超過伺服器的網卡的上限值,可以考慮使用分布式來進行分流5.離線計算,需要中間環節緩衝等別的需求
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.用戶端向目標節點發送命令,擷取命令執行結果 

需要注意的是:用戶端不會自動找到目標節點執行命令

槽命中:直接返回

[[email protected] ~]# redis-cli -p 9002 cluster keyslot hello(integer) 866

槽不命中:moved異常

[[email protected] ~]# redis-cli -p 9002 cluster keyslot php(integer) 9244

[[email protected] ~]# redis-cli -c -p 9002127.0.0.1:9002> cluster keyslot hello(integer) 866127.0.0.1:9002> set hello world-> Redirected to slot [866] located at 192.168.81.100:9003OK192.168.81.100:9003> cluster keyslot python(integer) 7252192.168.81.100:9003> set python best-> Redirected to slot [7252] located at 192.168.81.101:9002OK192.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[[email protected] ~]# redis-cli -p 9002127.0.0.1:9002> cluster keyslot python(integer) 7252127.0.0.1:9002> set python bestOK127.0.0.1:9002> set hello world(error) MOVED 866 192.168.81.100:9003127.0.0.1:9002> exit[[email protected] ~]# 
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異常給JedisClusterJedisCluster會重新初始化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訊息給節點22.如果發送成功,代表節點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_tagcluster countkeysinslot {slot}擷取槽對應索引值個數

3.包含bigkey:例如大字串,幾百萬的元素的hash,set等

在從節點:redis-cli --bigkeys最佳化:最佳化資料結構

4.記憶體相關配置不一致

hash-max-ziplist-value:滿足一定條件情況下,hash可以使用ziplistset-max-intset-entries:滿足一定條件情況下,set可以使用intset在一個叢集內有若干個節點,當其中一些節點配置上面兩項最佳化,另外一部分節點沒有配置上面兩項最佳化當叢集中儲存hash或者set時,就會造成節點資料不均勻最佳化:定期檢查配置一致性

5.請求傾斜:熱點key

重要的key或者bigkeyRedis 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必須在一個slotkey事務和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 Cluster4.叢集伸縮通過在節點之間移動槽和相關資料實現    擴容時根據槽遷移計劃把槽從源節點遷移到新節點    收縮時如果下線的節點有負責的槽需要遷移到其他節點,再通過cluster forget命令讓叢集內所有節點忘記被下線節點5.使用smart用戶端操作叢集過到通訊效率最大化,用戶端內部負責計算維護鍵,槽以及節點的映射,用於快速定位到目標節點6.叢集自動容錯移轉過程分為故障發現和節點恢複。節點下線分為主觀下線和客觀下線,當超過半數節點認為故障節點為主觀下線時,標記這個節點為客觀下線狀態。從節點負責對客觀下線的主節點觸發故障恢複流程,保證叢集的可用性7.開發營運常見問題包括:超大規模叢集帶席消耗,pub/sub廣播問題,叢集傾斜問題,單機和叢集對比等

高可用Redis(十二):Redis Cluster

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.