1. 程式人生 > >【譯】Redis Cluster官方教程

【譯】Redis Cluster官方教程

摘要
這篇文章主要介紹redis cluster可用性和一致性相關的特性,值得一提的是,redis cluster需要高於等於redis3.0版本。


概要

這篇文章主要介紹redis cluster可用性和一致性相關的特性,值得一提的是,redis cluster需要高於等於redis3.0版本。

Redis Cluster 101
Redis Cluster提供了一種資料自動分片到不同Redis例項中的解決方案,Redis Cluster在一定程度上提高了Redis系統的可用性,即當一些節點掛掉之後,其他節點還可以繼續提供服務。而當大部分的master節點都掛掉的時候,Redis Cluster會停止服務。
因此Redis Cluster帶來了:

  1.     自動將資料分散到不同的節點。
  2.     允許當一些節點掛掉之後剩下的節點仍然可以工作,或者是禁止這些節點繼續工作。


Redis Cluster TCP ports
每一個Redis Cluster節點需要開兩個TCP埠,一個是用來處理客戶端的請求,例如6379埠,另一個埠由第一個埠加上10000之後得到即16379,第二個埠用來作為叢集匯流排,也就是叢集之間節點相互進行二進位制通訊用的。叢集匯流排的用處如下:

  •     錯誤檢測
  •     配置更新
  •     failover
  •     ……

客戶端的連線埠和叢集匯流排的連線埠之間的距離10000是固定的。為了讓Redis Cluster正常的工作,對於每一個節點:

  •     客戶端連線埠需要能夠和Cluster進行通訊,用於keys遷移。
  •     所有節點的Cluster埠能夠相互通訊。

如果這兩個埠沒有開啟,則Redis Cluster不能夠正常工作。
Cluster埠之間使用特殊的二進位制協議進行通訊,這種二進位制協議更適合節點之間通訊,可以佔用更小的頻寬和更少的傳輸時間。

Redis Cluster Docker
當前的Redis Cluster不支援NATted環境,Docker使用埠對映技術,也即執行在Docker容器內部的應用暴露在容器外面的埠和應用暴露的埠不一樣,這對於多個應用在Docker中使用同一個埠是非常重要的。為了讓Redis Cluster能夠在Docker中好好工作,我們需要檢查--net=host選項,更多的資訊見

Docket文件


Redis Cluster 資料 sharding
Redis Cluster不使用一致性雜湊,但是不同形式的sharding,每一個key理論上是hash slot的一部分。在Redis Cluster中有16384個hash slot,為了計算指定key的hash slot,我們簡單的使用CRC16演算法並對結果進行16384取模。在Redis Cluster中的每一個節點代表著所有hash slot的一個子集,例如我們有三個節點:

  •     Node A 包括0到5500之間的hash slots
  •     Node B 包括5501到11000之間的hash slots
  •     Node C 包括11001到16383之間的hash slots

這使得可以很容易的向Redis Cluster中新增或刪除節點。例如,我們想要新增一個節點D,我們需要將一些hash slots從A,B,C節點移給D。假如我們想要移除A節點,我們可以把A節點上原有的hash slots移動到B和C節點。當A節點的hash slots移除完畢之後,就可以把A節點下線了。
將hash slots從一個節點移動到其他節點不需要任何的停機操作。
Redis Cluster支援多key操作,多個key是通過一個命令、或者一個事務、或者一個lua指令碼執行的,屬於同一個hash slot。使用者可以強制多個key屬於同一個hash slot,這個概念叫hash tags。
Hash tags有關的介紹在Redis Cluster規範裡面有介紹,主旨是當key中包含{}的時候,只有{}括號內的字串才被用來hash。例如,一個key是this{key},另一個key是that{key},他們會被對映到同一個hash slot,而且可以被用於一批key一個命令的操作。


Redis Cluster master-slave模式
為了讓當某一個master掛掉之後,這個master的hash slot仍然可以使用,Redis Cluster使用master-slave模式,因此對於每一批hash slot來說都有N個備份,其中N-1個是slave。在我們的例子中,節點A、B、C,如果B掛了,則整個Redis Cluster就不能用了,因為沒有例項類服務5501-11000這部分hash slots。但是如果我們為每個master節點各增加一個slave節點,比如A1,B1,C1節點,如果B掛了,整個叢集還是可以正常工作的。
Node B1是B的複製,如果B掛了,Cluster將會選擇B1作為新的master,然後繼續工作。值得注意的是,如果B和B1同時掛了,那就沒轍了。


Redis Cluster一致性保證
Redis Cluster並不保證強一致性,也就是在一定條件下,Redis Cluster可能丟失被確認寫入的資料,第一個有可能Redis Cluster丟失資料的原因是因為複製是非同步進行的,意味著下面情景有可能發生:

  •     客戶端將資料寫入B
  •     master B回覆客戶端寫入成功
  •     master將寫命令傳播給B1,B2和B3

我們可以看到,在B回覆客戶端之前不會等到B1,B2,B3的應答。因此如果客戶端向B寫了資料,B確認了,但是在資料複製到B1,B2,B3之前掛了,那資料對於B1,B2,B3來說就丟失了。和傳統的資料庫類似,可以強制資料庫將日誌寫入磁碟再告知客戶端寫成功,但是這麼做帶來的效能損耗是非常大的,這對於Redis Cluster來說就是同步複製。
所以這就是一致性和可用性之間的權衡,如果確實需要,Redis Cluster是支援同步寫的,由WAIT命令實現,這可以保證儘量少的丟失資料,儘管Redis Cluster提供了同步複製的支援,但是Redis Cluster並沒有實現強一致性,因此在一些複雜的應用場景中,還是有可能丟失資料的。
另外一個數據會丟失的場景也值得一提,即當出現網路分割槽的時候,也就是某一個或多個master和其他的master失去了聯絡,舉個例子,我們有六個Redis例項,三個master和三個slave,還有一個client我們把它叫做Z1。當出現網路分割槽的時候,比如A,C,A1,B1,C1,處於一個分割槽,另一個分割槽有B和Z1。
Z1還可以向B寫資料,B也接受了Z1的寫請求,如果分割槽只持續一小段時間,Cluster仍然可以繼續工作。然而,如果時間足夠大,Cluster選舉了B1作為master,那麼之前Z1寫入的資料就丟失了。
值得一提的是在Z1還可以向B寫資料的時候,有一個最大的視窗時間,如果過了這個時間,Cluster選取了B1作為master,B就不能夠接受寫請求了。這段時間是非常重要的,這個時間被叫做node timeout。當node timeout之後,master被認為出問題了,並且可以被其slave代替,然後master不能夠處理寫請求。


Redis Cluster配置引數
cluster-enabled<yes/no>:如果是yes,則當前redis啟動為Redis Cluster的一個例項,否則當前Redis以單機模式啟動。

cluster-config-file<filename>:值得注意的是這個配置檔案是使用者不可編輯的,是由Redis 叢集節點自動建立的,每次節點狀態有變化的時候都會持久化這個配置檔案,也是為了Redis叢集節點重啟的時候重新讀取。配置檔案的內容包括叢集中的其他節點、他們的狀態、持久變數等等。每當接受到訊息的時候,檔案會被重新整理並且寫入磁碟。

cluster-node-timeout<milliseconds>:Redis叢集節點的超時時間,如果在這個時間內Redis叢集節點不可達,則叢集將會執行failover策略,將該master的slave節點選為master。這個引數控制Redis叢集重要的,值得提的是,如果指定時間當前節點聯絡不到大多數的master,則會拒絕服務。

cluster-slave-validity-factor<factor>:如果將該項設定為0,不管slave節點和master節點間失聯多久都會一直嘗試failover(設為正數,失聯大於一定時間(factor*節點TimeOut),不再進行FailOver)。比如,如果節點的timeout設定為5秒,該項設定為10,如果master跟slave之間失聯超過50秒,slave不會去failover它的master(意思是不會去把master設定為掛起狀態,並取代它)。注意:任意非0數值都有可能導致當master掛掉又沒有slave去failover它,這樣redis叢集不可用。在這種情況下只有原來那個master重新回到叢集中才能讓叢集恢復工作。

cluster-migration-barrier<count>:一個master可以擁有的最小slave數量。該項的作用是,當一個master沒有任何slave的時候,某些有富餘slave的master節點,可以自動的分一個slave給它。

cluster-require-full-coverage<yes/no>:如果該項設定為yes(預設就是yes) 當一定比例的鍵空間沒有被覆蓋到(就是某一部分的雜湊槽沒了,有可能是暫時掛了)叢集就停止處理任何查詢操作。如果該項設定為no,那麼就算請求中只有一部分的鍵可以被查到,一樣可以查詢(但是有可能會查不全)