本文檔匯總了多篇文章知識的結(jié)晶,整理出一份完整的Redis集群搭建教程,在本文最后也有注明摘自原文的地址旭寿,如果原作者有意見,可與我聯(lián)系崇败,侵刪盅称。
Step 0 :集群概念
Redis 集群簡介
Redis 集群是一個可以在多個 Redis 節(jié)點之間進行數(shù)據(jù)共享的設施(installation)。
Redis 集群不支持那些需要同時處理多個鍵的 Redis 命令后室, 因為執(zhí)行這些命令需要在多個 Redis 節(jié)點之間移動數(shù)據(jù)微渠, 并且在高負載的情況下, 這些命令將降低 Redis 集群的性能咧擂, 并導致不可預測的行為逞盆。
Redis 集群通過分區(qū)(partition)來提供一定程度的可用性(availability): 即使集群中有一部分節(jié)點失效或者無法進行通訊, 集群也可以繼續(xù)處理命令請求松申。
Redis 集群提供了以下兩個好處:
- 將數(shù)據(jù)自動切分(split)到多個節(jié)點的能力云芦。
- 當集群中的一部分節(jié)點失效或者無法進行通訊時俯逾, 仍然可以繼續(xù)處理命令請求的能力。
Redis 集群數(shù)據(jù)共享
Redis 集群使用數(shù)據(jù)分片(sharding)而非一致性哈希(consistency hashing)來實現(xiàn): 一個 Redis 集群包含 16384
個哈希槽(hash slot)舅逸, 數(shù)據(jù)庫中的每個鍵都屬于這 16384
個哈希槽的其中一個桌肴, 集群使用公式 CRC16(key) % 16384
來計算鍵 key
屬于哪個槽, 其中 CRC16(key)
語句用于計算鍵 key
的 CRC16 校驗和琉历。
集群中的每個節(jié)點負責處理一部分哈希槽坠七。 舉個例子, 一個集群可以有三個哈希槽旗笔, 其中:
- 節(jié)點 A 負責處理
0
號至5500
號哈希槽彪置。 - 節(jié)點 B 負責處理
5501
號至11000
號哈希槽。 - 節(jié)點 C 負責處理
11001
號至16384
號哈希槽蝇恶。
這種將哈希槽分布到不同節(jié)點的做法使得用戶可以很容易地向集群中添加或者刪除節(jié)點拳魁。 比如說:
- 如果用戶將新節(jié)點 D 添加到集群中, 那么集群只需要將節(jié)點 A 撮弧、B 潘懊、 C 中的某些槽移動到節(jié)點 D 就可以了。
- 與此類似贿衍, 如果用戶要從集群中移除節(jié)點 A 授舟, 那么集群只需要將節(jié)點 A 中的所有哈希槽移動到節(jié)點 B 和節(jié)點 C , 然后再移除空白(不包含任何哈希槽)的節(jié)點 A 就可以了贸辈。
因為將一個哈希槽從一個節(jié)點移動到另一個節(jié)點不會造成節(jié)點阻塞释树, 所以無論是添加新節(jié)點還是移除已存在節(jié)點, 又或者改變某個節(jié)點包含的哈希槽數(shù)量裙椭, 都不會造成集群下線。
Redis 集群中的主從復制
為了使得集群在一部分節(jié)點下線或者無法與集群的大多數(shù)(majority)節(jié)點進行通訊的情況下署浩, 仍然可以正常運作揉燃, Redis 集群對節(jié)點使用了主從復制功能: 集群中的每個節(jié)點都有 1
個至 N
個復制品(replica), 其中一個復制品為主節(jié)點(master)筋栋, 而其余的 N-1
個復制品為從節(jié)點(slave)炊汤。
在之前列舉的節(jié)點 A 、B 弊攘、C 的例子中抢腐, 如果節(jié)點 B 下線了, 那么集群將無法正常運行襟交, 因為集群找不到節(jié)點來處理 5501
號至 11000
號的哈希槽迈倍。
另一方面, 假如在創(chuàng)建集群的時候(或者至少在節(jié)點 B 下線之前)捣域, 我們?yōu)橹鞴?jié)點 B 添加了從節(jié)點 B1 啼染, 那么當主節(jié)點 B 下線的時候宴合, 集群就會將 B1 設置為新的主節(jié)點, 并讓它代替下線的主節(jié)點 B 迹鹅, 繼續(xù)處理 5501
號至 11000
號的哈希槽卦洽, 這樣集群就不會因為主節(jié)點 B 的下線而無法正常運作了。
不過如果節(jié)點 B 和 B1 都下線的話斜棚, Redis 集群還是會停止運作阀蒂。
Redis 集群的一致性保證(guarantee)
Redis 集群不保證數(shù)據(jù)的強一致性(strong consistency): 在特定條件下, Redis 集群可能會丟失已經(jīng)被執(zhí)行過的寫命令弟蚀。
使用異步復制(asynchronous replication)是 Redis 集群可能會丟失寫命令的其中一個原因蚤霞。 考慮以下這個寫命令的例子:
- 客戶端向主節(jié)點 B 發(fā)送一條寫命令。
- 主節(jié)點 B 執(zhí)行寫命令粗梭,并向客戶端返回命令回復争便。
- 主節(jié)點 B 將剛剛執(zhí)行的寫命令復制給它的從節(jié)點 B1 、 B2 和 B3 断医。
如你所見滞乙, 主節(jié)點對命令的復制工作發(fā)生在返回命令回復之后, 因為如果每次處理命令請求都需要等待復制操作完成的話鉴嗤, 那么主節(jié)點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權(quán)衡斩启。
如果真的有必要的話, Redis 集群可能會在將來提供同步地(synchronou)執(zhí)行寫命令的方法醉锅。
Redis 集群另外一種可能會丟失命令的情況是兔簇, 集群出現(xiàn)網(wǎng)絡分裂(network partition), 并且一個客戶端與至少包括一個主節(jié)點在內(nèi)的少數(shù)(minority)實例被孤立硬耍。
舉個例子垄琐, 假設集群包含 A 、 B 经柴、 C 狸窘、 A1 、 B1 坯认、 C1 六個節(jié)點翻擒, 其中 A 、B 牛哺、C 為主節(jié)點陋气, 而 A1 、B1 引润、C1 分別為三個主節(jié)點的從節(jié)點巩趁, 另外還有一個客戶端 Z1 。
假設集群中發(fā)生網(wǎng)絡分裂淳附, 那么集群可能會分裂為兩方晶渠, 大多數(shù)(majority)的一方包含節(jié)點 A 凰荚、C 、A1 褒脯、B1 和 C1 便瑟, 而少數(shù)(minority)的一方則包含節(jié)點 B 和客戶端 Z1 。
在網(wǎng)絡分裂期間番川, 主節(jié)點 B 仍然會接受 Z1 發(fā)送的寫命令:
- 如果網(wǎng)絡分裂出現(xiàn)的時間很短到涂, 那么集群會繼續(xù)正常運行;
- 但是颁督, 如果網(wǎng)絡分裂出現(xiàn)的時間足夠長践啄, 使得大多數(shù)一方將從節(jié)點 B1 設置為新的主節(jié)點, 并使用 B1 來代替原來的主節(jié)點 B 沉御, 那么 Z1 發(fā)送給主節(jié)點 B 的寫命令將丟失屿讽。
注意, 在網(wǎng)絡分裂出現(xiàn)期間吠裆, 客戶端 Z1 可以向主節(jié)點 B 發(fā)送寫命令的最大時間是有限制的伐谈, 這一時間限制稱為節(jié)點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
- 對于大多數(shù)一方來說试疙, 如果一個主節(jié)點未能在節(jié)點超時時間所設定的時限內(nèi)重新聯(lián)系上集群诵棵, 那么集群會將這個主節(jié)點視為下線, 并使用從節(jié)點來代替這個主節(jié)點繼續(xù)工作祝旷。
- 對于少數(shù)一方履澳, 如果一個主節(jié)點未能在節(jié)點超時時間所設定的時限內(nèi)重新聯(lián)系上集群, 那么它將停止處理寫命令怀跛, 并向客戶端報告錯誤距贷。