標籤:
一、Redis叢集
Redis的叢集實現是內建資料自動分區機制,叢集內部將所有的key映射到16384個Slot中,叢集中的每個Redis Instance負責其中的一部分的Slot的讀寫。叢集用戶端串連叢集中任一Redis Instance即可發送命令,當Redis Instance收到自己不負責的Slot的請求時,會將負責請求Key所在Slot的Redis Instance地址返回給用戶端,用戶端收到後自動將原請求重新發往這個地址,對外部透明。一個Key到底屬於哪個Slot由crc16(key) % 16384 決定。
注意:叢集必須要3個以上的的主節點,否則在建立叢集時會失敗,我們在後續會實踐到。
所以,我們假設現在有3個節點已經組成了叢集,分別是:A, B, C 三個節點,它們可以是一台機器上的三個連接埠,也可以是三台不同的伺服器。那麼,採用雜湊槽 (hash slot)的方式來分配16384個slot 的話,它們三個節點分別承擔的slot 區間是:
- 節點A覆蓋0-5460;
- 節點B覆蓋5461-10922;
- 節點C覆蓋10923-16383.
二、Redis叢集的主從模型
為了當部分節點失效時,或者無法與大多數節點通訊時仍能保持可用,Redis叢集採用每個節點擁有1(主服務自身)到N個副本(N-1個附加的從伺服器)的主從模型。
在我們的例子中,叢集擁有A,B,C三個節點,如果節點B失效叢集將不能繼續服務,因為我們不再有辦法來服務在5501-11000範圍內的雜湊槽。
但是,如果當我們建立叢集後(或者稍後),我們為每一個主伺服器添加一個從伺服器,這樣最終的叢集就由主伺服器A,B,C和從伺服器A1,B1,C1組成,如果B節點失效系統仍能繼續服務。
B1節點複製B節點,於是叢集會選舉B1節點作為新的主伺服器,並繼續正確的運轉。
三、Redis叢集的一致性保證
Redis叢集不保證強一致性。實踐中,這意味著在特定的條件下,Redis叢集可能會丟掉一些被系統收到的寫入請求命令。
Redis叢集為什麼會丟失寫請求的第一個原因,是因為採用了非同步複製。這意味著在寫期間下面的事情發生了:
- 你的用戶端向主伺服器B寫入。
- 主伺服器B回複OK給你的用戶端。
- 主伺服器B傳播寫入操作到其從伺服器B1,B2和B3。
你可以看到,B在回複用戶端之前沒有等待從B1,B2,B3的確認,因為這是一個過高的延遲代價,所以如果你的用戶端寫入什麼東西,B確認了這個寫操作,但是在發送寫操作到其從伺服器前崩潰了,其中一個從伺服器被提升為主伺服器,永久性的丟失了這個寫操作。
這非常類似於在大多數被配置為每秒重新整理資料到磁碟的資料庫發生的事情一樣,這是一個可以根據以往不包括分布式系統的傳統資料庫系統的經驗來推理的情境。同樣的,你可以通過在回複用戶端之前強制資料庫重新整理資料到磁碟來改進一致性,但這通常會極大的降低效能。
基本上,有一個效能和一致性之間的權衡。
注意:未來,Redis叢集在必要時可能或允許使用者執行同步寫操作。
Redis叢集丟失寫操作還有另一個情境,發生在網路分割時,用戶端與至少包含一個主伺服器的少數執行個體被孤立起來了。
舉個例子,我們的叢集由A,B,C,A1,B1,C1共6個節點群組成,3個主伺服器,3個從伺服器。還有一個用戶端,我們稱為Z1。
分割發生以後,有可能分割的一側是A,C,A1,B1,C1,分割的另一側是B和Z1。Z1仍然可以寫入到可接受寫請求的B。如果分割在很短的時間內恢複,叢集會正常的繼續。但是,如果分割持續了足夠的時間,B1在分割的大多數這一側被提升為主伺服器,Z1發送給B的寫請求會丟失。
注意,Z1發送給B的寫運算元量有一個最大視窗:如果分割的大多數側選舉一個從伺服器為主伺服器後過了足夠多的時間,少數側的每一個主伺服器節點將停止接受寫請求。
這個時間量是Redis叢集一個非常重要的配置指令,稱為節點逾時(node timeout)。
節點逾時時間過後,主伺服器節點被認為失效,可以用其一個副本來取代。同樣地,節點逾時時間過後,主伺服器節點還不能感知其它主伺服器節點的大多數,則進入錯誤狀態,並停止接受寫請求。
Redis Cluster原理