本文檔匯總了多篇文章知識的結晶,整理出一份完整的Redis集群搭建教程,在本文最后也有注明摘自原文的地址,如果原作者有意見,可與我聯系,侵刪。
Step 0 :集群概念
Redis 集群簡介
Redis 集群是一個可以在多個 Redis 節點之間進行數據共享的設施(installation)。
Redis 集群不支持那些需要同時處理多個鍵的 Redis 命令, 因為執行這些命令需要在多個 Redis 節點之間移動數據, 并且在高負載的情況下, 這些命令將降低 Redis 集群的性能, 并導致不可預測的行為。
Redis 集群通過分區(partition)來提供一定程度的可用性(availability): 即使集群中有一部分節點失效或者無法進行通訊, 集群也可以繼續處理命令請求。
Redis 集群提供了以下兩個好處:
- 將數據自動切分(split)到多個節點的能力。
- 當集群中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力。
Redis 集群數據共享
Redis 集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384
個哈希槽(hash slot), 數據庫中的每個鍵都屬于這 16384
個哈希槽的其中一個, 集群使用公式 CRC16(key) % 16384
來計算鍵 key
屬于哪個槽, 其中 CRC16(key)
語句用于計算鍵 key
的 CRC16 校驗和。
集群中的每個節點負責處理一部分哈希槽。 舉個例子, 一個集群可以有三個哈希槽, 其中:
- 節點 A 負責處理
0
號至5500
號哈希槽。 - 節點 B 負責處理
5501
號至11000
號哈希槽。 - 節點 C 負責處理
11001
號至16384
號哈希槽。
這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。 比如說:
- 如果用戶將新節點 D 添加到集群中, 那么集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
- 與此類似, 如果用戶要從集群中移除節點 A , 那么集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然后再移除空白(不包含任何哈希槽)的節點 A 就可以了。
因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。
Redis 集群中的主從復制
為了使得集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作, Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1
個至 N
個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1
個復制品為從節點(slave)。
在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那么集群將無法正常運行, 因為集群找不到節點來處理 5501
號至 11000
號的哈希槽。
另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那么當主節點 B 下線的時候, 集群就會將 B1 設置為新的主節點, 并讓它代替下線的主節點 B , 繼續處理 5501
號至 11000
號的哈希槽, 這樣集群就不會因為主節點 B 的下線而無法正常運作了。
不過如果節點 B 和 B1 都下線的話, Redis 集群還是會停止運作。
Redis 集群的一致性保證(guarantee)
Redis 集群不保證數據的強一致性(strong consistency): 在特定條件下, Redis 集群可能會丟失已經被執行過的寫命令。
使用異步復制(asynchronous replication)是 Redis 集群可能會丟失寫命令的其中一個原因。 考慮以下這個寫命令的例子:
- 客戶端向主節點 B 發送一條寫命令。
- 主節點 B 執行寫命令,并向客戶端返回命令回復。
- 主節點 B 將剛剛執行的寫命令復制給它的從節點 B1 、 B2 和 B3 。
如你所見, 主節點對命令的復制工作發生在返回命令回復之后, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那么主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。
如果真的有必要的話, Redis 集群可能會在將來提供同步地(synchronou)執行寫命令的方法。
Redis 集群另外一種可能會丟失命令的情況是, 集群出現網絡分裂(network partition), 并且一個客戶端與至少包括一個主節點在內的少數(minority)實例被孤立。
舉個例子, 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, 而 A1 、B1 、C1 分別為三個主節點的從節點, 另外還有一個客戶端 Z1 。
假設集群中發生網絡分裂, 那么集群可能會分裂為兩方, 大多數(majority)的一方包含節點 A 、C 、A1 、B1 和 C1 , 而少數(minority)的一方則包含節點 B 和客戶端 Z1 。
在網絡分裂期間, 主節點 B 仍然會接受 Z1 發送的寫命令:
- 如果網絡分裂出現的時間很短, 那么集群會繼續正常運行;
- 但是, 如果網絡分裂出現的時間足夠長, 使得大多數一方將從節點 B1 設置為新的主節點, 并使用 B1 來代替原來的主節點 B , 那么 Z1 發送給主節點 B 的寫命令將丟失。
注意, 在網絡分裂出現期間, 客戶端 Z1 可以向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱為節點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
- 對于大多數一方來說, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么集群會將這個主節點視為下線, 并使用從節點來代替這個主節點繼續工作。
- 對于少數一方, 如果一個主節點未能在節點超時時間所設定的時限內重新聯系上集群, 那么它將停止處理寫命令, 并向客戶端報告錯誤。