Docker實現
1.第一步:搭建redis集群專用的docker網絡
docker network create net-redis --subnet 172.23.0.0/16
# --subnet 它定義了網絡內部容器可以使用的 IP 地址范圍。
2.第二步:構建redis.conf文件
#!/bin/bash for port in $(seq 1 6);do mkdir -p /mydata/redis/node-${port}/conf touch /mydata/redis/node-${port}/conf/redis.conf cat << TTT > /mydata/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.23.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes TTT done
配置解釋
port 6379: 含義: 指定 Redis 實例監聽的端口號。 作用: 客戶端通過這個端口連接到 Redis 服務器。 默認值: 6379 bind 0.0.0.0: 含義: 指定 Redis 實例監聽的網絡接口地址。 作用: 0.0.0.0 表示監聽所有可用的網絡接口。這意味著 Redis 實例可以接受來自任何 IP 地址的連接請求。 注意:在生產環境中,通常不建議使用 0.0.0.0,因為它會增加安全風險。 建議綁定到特定的內網 IP 地址。 默認值: 127.0.0.1 (只允許本地連接) cluster-enabled yes: 含義: 啟用 Redis 集群模式。 作用: 將 Redis 實例配置為集群模式的節點。 默認值: no (禁用集群模式) cluster-config-file nodes.conf: 含義: 指定集群配置文件名。 作用: Redis 集群使用此文件來存儲集群的配置信息,例如節點信息、槽位分配等。 此文件由 Redis 自動維護,不應手動修改。 默認值: 無 (如果沒有啟用集群模式,則不需要配置此項) cluster-node-timeout 5000: 含義: 指定集群節點超時時間,單位為毫秒。 作用: 如果一個節點在指定的時間內沒有收到來自其他節點的 ping 消息,則認為該節點已失效。 默認值: 15000 (15 秒) cluster-announce-ip 172.23.0.1${port}: 含義: 指定集群節點對外公布的 IP 地址。 作用: 告知集群中的其他節點,本節點的IP地址是什么。 重點: 172.23.0.1${port}是一個模板字符串。 ${port}會被實際的端口號替換。所以,如果port變量是 6379,那么最終的地址會是 172.23.0.16379。 這幾乎肯定是一個錯誤配置! 端口號不應該直接附加在IP地址后面。正確的配置應該是獨立的設置端口。這個配置會導致節點無法正確加入集群。 cluster-announce-port 6379: 含義: 指定集群節點對外公布的客戶端連接端口。 作用: 告知集群中的其他節點,本節點用于客戶端連接的端口號。 默認值: 與 port 配置相同 cluster-announce-bus-port 16379: 含義: 指定集群節點間通信的總線端口。 作用: 集群節點之間使用此端口進行數據同步、故障轉移等操作。 此端口通常是客戶端連接端口 + 10000。 默認值: 與 port 配置的端口號 + 10000。 appendonly yes: 含義: 啟用 AOF (Append Only File) 持久化。 作用: 將每個寫命令追加到 AOF 文件中,以保證數據的持久性。 即使 Redis 服務器崩潰,也可以通過 AOF 文件恢復數據。 默認值: no (禁用 AOF 持久化) 總結和注意事項: 安全性: bind 0.0.0.0 在生產環境中存在安全風險,應該綁定到特定的內網 IP 地址。 cluster-announce-ip: cluster-announce-ip 172.23.0.1${port} 絕對是錯誤的。${port}會被直接追加到IP地址后,生成一個無效的地址。正確的配置方式是不使用模板字符串,直接指定一個有效的IP地址,或者使用環境變量替換,但要確保替換后的結果是有效的IP地址。 cluster-announce-ip的作用非常重要,它告訴其他節點如何連接到當前節點。 端口: 確保客戶端連接端口 (cluster-announce-port) 和集群總線端口 (cluster-announce-bus-port) 沒有被防火墻阻止。 持久化: appendonly yes 啟用 AOF 持久化可以保證數據的持久性,但會影響性能。 可以根據實際需求選擇 AOF 或 RDB 持久化方式,或者同時啟用兩種持久化方式。
第三步:啟動容器
#!/bin/bash for port in $(seq 1 6); do docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net net-redis --ip 172.23.0.1${port} redis redis-server /etc/redis/redis.conf done echo "Redis docker generated successfully."
第四步:進入到任意一個容器內,進入該容器的redis客戶端中執行創建集群的命令
docker exec -it redis-1 /bin/bash redis-cli --cluster create 172.23.0.11:6379 172.23.0.12:6379 172.23.0.13:6379 172.23.0.14:6379 172.23.0.15:6379 172.23.0.16:6379 --cluster-replicas 1
# 參數解釋
--cluster-replicas 1參數告訴redis-cli在創建集群時,為每個主節點創建一個副本節點。
由于你提供了 6 個節點,redis-cli 會自動將它們組織成 3 個主節點和 3 個副本節點。 具體分配是:
172.23.0.11:6379是主節點,172.23.0.12:6379是它的副本。172.23.0.13:6379是主節點,172.23.0.14:6379是它的副本。172.23.0.15:6379是主節點,172.23.0.16:6379是它的副本。
redis-cli 會盡可能地均勻分配槽給各個主節點。 副本節點不存儲任何槽的分配信息,它們只是簡單地復制主節點的數據。
總結:
--cluster-replicas 參數控制著集群中主節點和副本節點的比例。 如果你設置 --cluster-replicas 0,那么就不會創建任何副本節點,所有節點都將成為主節點。
如果你的目標是創建更多的主節點而不是副本,你需要使用不同的節點組合來創建集群,或者直接手動添加節點到現有的集群。 請注意,redis集群節點數量最好是奇數,避免腦裂。
步驟成功的圖片

如何查看節點角色:
redis-cli -h 172.23.0.11 -p 6379 cluster nodes

至此三主三從的redis節點搭建完畢
常見疑問點:
一.單主多從和多主多從的區別
多主多從的 Redis 集群架構相比于單主多從的架構,主要優勢體現在以下幾個方面:
1. 擴展性(Scalability):
- 水平擴展: 多主架構允許通過增加主節點來水平擴展集群的容量。 單主架構的寫入性能受到單個主節點的限制,而多主架構可以將寫入負載分散到多個主節點上,從而提高整體寫入吞吐量。
- 更高的吞吐量: 更多的節點參與數據處理,顯著提高讀寫吞吐量。
2. 性能(Performance):
- 寫入性能: 如上所述,多主架構可以分散寫入負載,提高整體寫入性能。
- 并發處理能力: 多主架構能夠并發處理更多的客戶端請求,降低延遲。
3. 高可用性(High Availability):
- 更強的容錯能力: 如果一個主節點宕機,只有其負責的槽會受到影響,其他主節點仍然可以繼續提供服務。 單主架構中,如果主節點宕機,整個集群的寫入服務都會中斷,直到故障轉移完成。
- 更快的故障恢復: 多主架構中,每個主節點只需要處理一部分槽的故障轉移,因此故障恢復速度更快。
4. 資源利用率(Resource Utilization):
- 更均衡的資源利用: 多主架構可以將負載分散到多個節點上,從而更均衡地利用集群中的資源。 單主架構中,主節點的負載較高,而副本節點的負載較低。
總結:
- 多主多從的 Redis 集群更適合需要高擴展性、高性能和高可用性的場景。 它可以處理更大的數據量,支持更高的并發訪問,并且具有更強的容錯能力。
- 單主多從的 Redis 架構更適合讀多寫少的場景,或者數據量較小,對擴展性和可用性要求不高的場景。 它的配置和管理相對簡單。
更詳細的對比:
| 特性 | 單主多從 | 多主多從 |
|---|---|---|
| 擴展性 | 有限,受單個主節點限制 | 高,可以通過增加主節點水平擴展 |
| 性能 | 讀性能好,寫性能受主節點限制 | 讀寫性能均好,可以分散寫入負載 |
| 可用性 | 主節點宕機影響所有寫入服務,故障轉移時間長 | 主節點宕機只影響部分槽,故障轉移時間短 |
| 資源利用率 | 主節點負載高,從節點負載低 | 資源利用更均衡 |
| 復雜性 | 簡單 | 相對復雜 |
| 適用場景 | 讀多寫少,數據量小,對擴展性和可用性要求不高 | 高并發,大數據量,對擴展性和可用性要求高 |
選擇建議:
在選擇 Redis 架構時,需要根據實際業務需求進行權衡。 如果你的業務需要處理大量的數據和高并發的訪問,并且對可用性有很高的要求,那么 Redis 集群(多主多從)是更好的選擇。 如果你的業務數據量較小,并發訪問量不高,并且可以容忍一定的故障恢復時間,那么單主多從的 Redis 架構可能更適合你
二、多住多從有哨兵機制嗎?
沒有。 Redis 集群(多主多從)本身就內置了故障檢測和自動故障轉移機制,不需要額外的哨兵(Sentinel)。
原因:
- 集群節點間的 Gossip 協議: Redis 集群使用 Gossip 協議進行節點間的通信,每個節點都會定期與其他節點交換信息,包括節點的狀態、角色、負責的槽等。 通過這種方式,集群中的每個節點都能了解集群的整體狀態。
- 內置的故障檢測機制: 每個節點都會定期 ping 其他節點,如果一個節點在一定時間內沒有收到另一個節點的回復,它會將該節點標記為
PFAIL(Possible Fail,可能失效)。 如果集群中有足夠多的節點都認為該節點失效,該節點會被標記為FAIL(Fail,失效)。 - 自動故障轉移: 當一個主節點被標記為
FAIL時,其副本節點會參與故障轉移的投票過程。 得票數最多的副本節點會被提升為新的主節點,并接管原主節點負責的槽。 這個過程是自動進行的,不需要人工干預。
與哨兵的區別:
- 哨兵: 是獨立的進程,用于監控 Redis 主節點的健康狀態,并在主節點宕機時自動進行故障轉移。
- Redis 集群: 故障檢測和故障轉移機制內置在集群節點中,不需要額外的進程。
總結:
Redis 集群自帶故障檢測和自動故障轉移功能,已經提供了高可用性,所以不需要再使用哨兵。 兩者是互斥的。 你要么使用 Redis 集群,要么使用哨兵來監控 Redis 主從復制架構。 同時使用 Redis 集群和哨兵是多余的,而且可能會導致沖突。
為什么不需要哨兵?
Redis 集群的設計目標之一就是提供高可用性,而其內置的故障檢測和自動故障轉移機制已經能夠很好地滿足這一需求。 使用哨兵會增加系統的復雜性,并且可能會引入額外的故障點。 因此,Redis 集群的設計者選擇將故障檢測和故障轉移機制集成到集群節點中,從而簡化了系統的架構。
注意:
如果你在使用 Redis 集群,并且之前配置了哨兵,應該移除哨兵配置,以避免沖突。
三、多主多從應該如何查詢數據呢?
在多主多從的 Redis 集群中查詢數據,你需要一個客戶端能夠感知 Redis 集群拓撲,并能夠根據 Key 自動路由到正確的主節點上。 你不需要手動去查找數據位于哪個主節點。
以下是幾種常見的查詢數據的方式和原理:
1. 使用支持集群的客戶端:
這是最推薦也是最常見的方式。 大部分主流編程語言的 Redis 客戶端都提供了對 Redis 集群的支持。 這些客戶端能夠自動地進行如下操作:
- 集群拓撲發現: 客戶端會連接到集群中的一個或多個節點,然后通過
CLUSTER NODES命令獲取整個集群的拓撲信息,包括每個節點的地址、角色、負責的槽等。 - Key 的哈希槽計算: 客戶端會根據你要查詢的 Key 使用一定的哈希算法(默認為 CRC16)計算出 Key 對應的哈希槽(Slot)。 Redis 集群將整個 Key 空間劃分為 16384 個哈希槽。
- 路由到正確的節點: 客戶端會根據 Key 的哈希槽,找到負責該槽的主節點,然后將查詢請求發送到該節點。
- 重定向處理 (MOVED 和 ASK): 如果客戶端發送請求到錯誤的節點,Redis 節點會返回
MOVED或ASK錯誤。MOVED表示 Key 的哈希槽已經遷移到另一個節點,客戶端會更新其拓撲信息,然后將請求發送到新的節點。ASK表示 Key 的哈希槽正在遷移到另一個節點,客戶端會先向目標節點發送ASKING命令,然后將請求發送到目標節點。
示例 (Python with redis-py-cluster):
from rediscluster import RedisCluster # 集群的啟動節點 startup_nodes = [{"host": "127.0.0.1", "port": "7000"}, {"host": "127.0.0.1", "port": "7001"}, {"host": "127.0.0.1", "port": "7002"}] # 創建集群客戶端 rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True) # 設置鍵值對 rc.set("mykey", "myvalue") # 獲取鍵值對 value = rc.get("mykey") print(value) # 輸出: myvalue
在這個例子中,你只需要指定集群的啟動節點,客戶端會自動發現整個集群的拓撲,并根據 Key "mykey" 找到負責該 Key 的主節點,然后執行 set 和 get 操作。 你不需要關心 Key 位于哪個主節點。
2. 手動計算哈希槽并連接到對應的節點 (不推薦):
這種方式非常麻煩,不推薦使用。 你需要手動計算 Key 的哈希槽,然后根據集群的拓撲信息找到負責該槽的主節點,最后連接到該節點并執行查詢。 這種方式容易出錯,而且需要手動處理重定向等問題。
具體步驟如下:
- 獲取集群拓撲: 使用
CLUSTER NODES命令連接到集群中的一個節點,獲取集群的拓撲信息。 - 計算哈希槽: 使用 CRC16 算法計算 Key 的哈希值,然后對 16384 取模,得到 Key 的哈希槽。
slot = crc16(key) % 16384 - 找到對應的節點: 根據哈希槽,從集群拓撲信息中找到負責該槽的主節點。
- 連接到節點并查詢: 連接到該主節點,并執行查詢操作。
- 處理重定向: 如果收到
MOVED或ASK錯誤,需要更新拓撲信息,并按照錯誤信息中的指示重定向到新的節點。
為什么不推薦手動計算哈希槽?
- 復雜性: 手動計算哈希槽和處理重定向邏輯非常復雜,容易出錯。
- 維護困難: 集群拓撲可能會動態變化,手動維護拓撲信息非常困難。
- 性能損失: 手動計算哈希槽和處理重定向邏輯會帶來額外的性能開銷。
總結:
使用支持集群的客戶端是查詢 Redis 集群數據的最佳方式。 客戶端會自動處理集群拓撲發現、Key 的哈希槽計算、路由和重定向等問題,你只需要像使用單機 Redis 一樣使用客戶端即可。 避免手動計算哈希槽和連接到對應的節點,因為這會增加復雜性和維護成本。
浙公網安備 33010602011771號