Redis 集羣是一個提供在多個Redis間節點間共享數據的程序集。html
Redis集羣並不支持處理多個keys的命令,由於這須要在不一樣的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的狀況下可能會致使不可預料的錯誤.node
Redis 集羣經過分區來提供必定程度的可用性,在實際環境中當某個節點宕機或者不可達的狀況下繼續處理命令. Redis 集羣的優點:redis
Redis 集羣沒有使用一致性hash, 而是引入了 哈希槽的概念.數據庫
Redis 集羣有16384個哈希槽,每一個key經過CRC16校驗後對16384取模來決定放置哪一個槽.集羣的每一個節點負責一部分hash槽,舉個例子,好比當前集羣有3個節點,那麼:網絡
這種結構很容易添加或者刪除節點. 好比若是我想新添加個節點D, 我須要從節點 A, B, C中得部分槽到D上. 若是我想移除節點A,須要將A中的槽移到B和C節點上,而後將沒有任何槽的A節點從集羣中移除便可. 因爲從一個節點將哈希槽移動到另外一個節點並不會中止服務,因此不管添加刪除或者改變某個節點的哈希槽的數量都不會形成集羣不可用的狀態.異步
爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有N-1個複製品.性能
在咱們例子中具備A,B,C三個節點的集羣,在沒有複製模型的狀況下,若是節點B失敗了,那麼整個集羣就會覺得缺乏5501-11000這個範圍的槽而不可用.優化
然而若是在集羣建立的時候(或者過一段時間)咱們爲每一個節點添加一個從節點A1,B1,C1,那麼整個集羣便有三個master節點和三個slave節點組成,這樣在節點B失敗後,集羣便會選舉B1爲新的主節點繼續服務,整個集羣便不會由於槽找不到而不可用了spa
不過當B和B1 都失敗後,集羣是不可用的.code
Redis 並不能保證數據的強一致性. 這意味這在實際中集羣在特定的條件下可能會丟失寫操做.
第一個緣由是由於集羣是用了異步複製. 寫操做過程:
主節點對命令的複製工做發生在返回命令回覆以後, 由於若是每次處理命令請求都須要等待複製操做完成的話, 那麼主節點處理命令請求的速度將極大地下降 —— 咱們必須在性能和一致性之間作出權衡。 注意:Redis 集羣可能會在未來提供同步寫的方法。 Redis 集羣另一種可能會丟失命令的狀況是集羣出現了網絡分區, 而且一個客戶端與至少包括一個主節點在內的少數實例被孤立。
舉個例子 假設集羣包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 爲主節點, A1 、B1 、C1 爲A,B,C的從節點, 還有一個客戶端 Z1 假設集羣中發生網絡分區,那麼集羣可能會分爲兩方,大部分的一方包含節點 A 、C 、A1 、B1 和 C1 ,小部分的一方則包含節點 B 和客戶端 Z1 .
Z1仍然可以向主節點B中寫入, 若是網絡分區發生時間較短,那麼集羣將會繼續正常運做,若是分區的時間足夠讓大部分的一方將B1選舉爲新的master,那麼Z1寫入B中得數據便丟失了.
注意, 在網絡分裂出現期間, 客戶端 Z1 能夠向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱爲節點超時時間(node timeout), 是 Redis 集羣的一個重要的配置選項:
Redis 集羣支持在集羣運行過程當中添加或移除節點。實際上,添加或移除節點都被抽象爲同一個操做,那就是把哈希槽從一個節點移到另外一個節點。
爲了理解這是怎麼工做的,咱們須要介紹 CLUSTER 的子命令,這些命令是用來操做 Redis 集羣節點上的哈希槽轉換表(slots translation table)。
如下是可用的子命令:
CLUSTER ADDSLOTS
slot1 [slot2] … [slotN]CLUSTER DELSLOTS
slot1 [slot2] … [slotN]CLUSTER SETSLOT
slot NODE nodeCLUSTER SETSLOT
slot MIGRATING nodeCLUSTER SETSLOT
slot IMPORTING node當 SETSLOT 子命令使用 NODE 形式的時候,用來給指定 ID 的節點指派哈希槽。 除此以外哈希槽能經過兩個特殊的狀態來設定,MIGRATING 和 IMPORTING:
這麼講可能顯得有點奇怪,如今咱們用實例讓它更清晰些。假設咱們有兩個 Redis 節點,稱爲 A 和 B。咱們想要把哈希槽 8 從 節點A 移到 節點B,因此咱們發送了這樣的命令:
其餘全部節點在每次被詢問到的一個鍵是屬於哈希槽 8 的時候,都會把客戶端引向節點」A」。具體以下:
這種方式讓咱們能夠不用在節點 A 中建立新的鍵。同時,一個叫作 redis-trib 的特殊客戶端,它也是 Redis 集羣的配置程序(configuration utility),會確保把已存在的鍵從節點 A 移到節點 B。這經過如下命令實現:
CLUSTER GETKEYSINSLOT slot count
上面這個命令會返回指定的哈希槽中 count 個鍵。對於每一個返回的鍵,redis-trib 向節點 A 發送一個 MIGRATE 命令,這樣會以原子性的方式(在移動鍵的過程當中兩個節點都被鎖住,以避免出現競爭情況)把指定的鍵從節點 A 移到節點 B。如下是 MIGRATE 的工做原理:
MIGRATE target_host target_port key target_database id timeout
執行 MIGRATE 命令的節點會鏈接到目標節點,把序列化後的 key 發送過去,一旦收到 OK 回覆就會從它本身的數據集中刪除老的 key。因此從一個外部客戶端看來,在某個時間點,一個 key 要不就存在於節點 A 中要不就存在於節點 B 中。
在 Redis 集羣中,不須要指定一個除了 0 號以外的數據庫,但 MIGRATE 命令能用於其餘跟 Redis 集羣無關的的任務,因此它是一個足夠通用的命令。MIGRATE 命令被優化了,使得即便在移動像長列表這樣的複雜鍵仍然能作到快速。 不過當在重配置一個擁有不少鍵且鍵的數據量都很大的集羣的時候,這個過程就並不那麼好了,對於使用數據庫的應用程序來講就會有延時這個限制。
參數文檔:http://www.redis.cn/topics/cluster-spec.html、http://www.redis.cn/topics/cluster-tutorial.html