虛擬槽分區
redis集群使用的是基于hash的一種分區算法,稱之為虛擬槽分區。
虛擬槽算法巧妙地使用了哈希空間,使用分散度良好的哈希函數將數據映射到一個固定范圍內的整數集合,整數集合中的每個整數稱為一個槽(slot) ,這個整數范圍遠遠大于節點數。槽是集群內數據管理;和遷移的基本單位。采用大范圍槽的主要目的是為了方便數據拆分和集群擴展。每個節點會負責一定數量的槽,如圖所示:
當前集群有5個節點,每個節點平均大約負責3276個槽。由于采用高質量的哈希算法,每個槽所映射的數據通常比較均勻,將數據平均劃分到 5個節點進行數據分區。
這種結構很容易添加或者刪除 節點。如果增加一個節點 6,就需要從節點 1 ~ 5 獲得部分槽分配到節點 6 上。如果想移除節點 1,需要將節點 1 中的槽移到節點 2 ~ 5 上,然后將沒有任何槽的節點 1 從集群中移除即可。
由于從一個節點將哈希槽移動到另一個節點并不會停止服務,所以無論添加刪除或者改變某個節點的哈希槽的數量都不會造成集群不可用的狀態。
Redis的數據分區
Redis Cluster 采用CRC16哈希函數+取余方法將數據分為16384個數據槽中:
slot = CRC16(key)& 16383
集群中每個節點負責一部分槽以及槽所映射的鍵值數據。
優點
- 解耦數據和節點之間的關系,簡化了節點擴容和收縮難度。
- 節點自身維護槽的映射關系,不需要客戶端或者代理服務維護槽分區元數據。
- 支持節點、槽、鍵之間的映射查詢,用于數據路由、在線伸縮等場景。
問題
- key的批量操作命令會失效
- key的事務操作失效
- 不支持多數據庫空間,只使用db0
- 復制結構只支持一層
數據定位
在redis集群啟動時,需要指定每個節點各自管理的槽。當節點啟動時,需要發握手命令使得節點相互連通,節點會互發管理信息。此時集群的狀態為down。當節點確定所有的數據槽都有相應的節點管理時,集群狀態修改為up,可以進行數據管理。
客戶端只需要連接到一個節點,即可進行數據操作。該節點接收到數據命令時,會根據key計算數據槽:若歸自己管理,則直接執行命令并返回結果;若不歸自己管理,則發送MOVEN命令給客戶端,告訴客戶端相應的服務器位置,客戶端重定向到正確的服務器上執行命令。
數據遷移
無論是新增還是減少一個節點,本質都是將該節點的數據遷移到另外一個或多個節點。
節點數據的遷移是以slot為單位的,具體流程:
- 在目標節點上聲明將從源節點上遷入
Slot CLUSTER SETSLOT <slot> IMPORTING <source_node_id>
- 在源節點上聲明將往目標節點遷出
Slot CLUSTER SETSLOT <slot> IMPORTING <source_node_id>
- 批量從源節點獲取
KEY CLUSTER GETKEYSINSLOT <slot> <count>
- 將獲取的Key遷移到目標節點
MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>
- 重復步驟3,4直到所有數據遷移完畢
- 分別向雙方節點發送
CLUSTER SETSLOT <slot> NODE <target_node_id>
,該命令將會廣播給集群其他節點,已經將Slot轉移到目標節點。 - 等待集群狀態變為OK
遷移過程并不會影響集群的狀態,集群可以正常提供數據讀寫服務:
當一個源節點受到一條已遷移數據命令時,源節點會發送一條ASK ip port
命令給客戶端,提示客戶端該數據所在數據槽已遷移到目標節點,客戶端會向MOVED命令一樣,重定向到目標節點上執行命令。
高可用
在Redis Cluster中,每個節點都應包含一個主節點和N個從節點,當主節點掛掉時,需要從節點選舉出一個從節點成為主節點,繼續管理相應的數據槽。
redis的主節點選舉算法為Raft算法