驚呆了,竟然可以用這種方式秒建Redis集群?
- 2020 年 3 月 28 日
- 筆記
前面我們講了《Redis 性能優化的 13 條軍規!》,其中最重要的一條就是使用 Redis 的集群功能,那麼本文我們就來看看,如何用 1s 鐘的時間來創建一個 Redis 集群。
Redis Cluster 是 Redis 3.0 版本推出的 Redis 集群方案,它將數據分布在不同的服務區上,以此來降低系統對單主節點的依賴,並且可以大大的提高 Redis 服務的讀寫性能。
Redis 將所有的數據分為 16384 個 slots(槽),每個節點負責其中的一部分槽位,當有 Redis 客戶端連接集群時,會得到一份集群的槽位配置資訊,這樣它就可以直接把請求命令發送給對應的節點進行處理。
Redis Cluster 是無代理模式去中心化的運行模式,客戶端發送的絕大數命令會直接交給相關節點執行,這樣大部分情況請求命令無需轉發,或僅轉發一次的情況下就能完成請求與響應,所以集群單個節點的性能與單機 Redis 伺服器的性能是非常接近的,因此在理論情況下,當水平擴展一倍的主節點就相當於請求處理的性能也提高了一倍,所以 Redis Cluster 的性能是非常高的。
Redis Cluster 架構圖如下所示:

搭建 Redis Cluster
Redis Cluster 的搭建方式有兩種,一種是使用 Redis 源碼中提供的 create-cluster 工具快速的搭建 Redis 集群環境,另一種是配置文件的方式手動創建 Redis 集群環境。
1.快速搭建 Redis Cluster
create-cluster 工具在 utils/create-cluster 目錄下,如下圖所示:

使用命令 ./create-cluster start
$ ./create-cluster start # 創建集群 Starting 30001 Starting 30002 Starting 30003 Starting 30004 Starting 30005 Starting 30006 複製程式碼
接下來我們需要把以上創建的 6 個節點節點通過 create 命令組成一個集群,執行如下:
[@iZ2ze0nc5n41zomzyqtksmZ:create-cluster]$ ./create-cluster create # 組建集群 >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:30005 to 127.0.0.1:30001 Adding replica 127.0.0.1:30006 to 127.0.0.1:30002 Adding replica 127.0.0.1:30004 to 127.0.0.1:30003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: 445f2a86fe36d397613839d8cc1ae6702c976593 127.0.0.1:30001 slots:[0-5460] (5461 slots) master M: 63bb14023c0bf58926738cbf857ea304bff8eb50 127.0.0.1:30002 slots:[5461-10922] (5462 slots) master M: 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc 127.0.0.1:30003 slots:[10923-16383] (5461 slots) master S: 64828ab44566fc5ad656e831fd33de87be1387a0 127.0.0.1:30004 replicates 445f2a86fe36d397613839d8cc1ae6702c976593 S: 0b17b00542706343583aa73149ec5ff63419f140 127.0.0.1:30005 replicates 63bb14023c0bf58926738cbf857ea304bff8eb50 S: e35f06ca9b700073472d72001a39ea4dfcb541cd 127.0.0.1:30006 replicates 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join . >>> Performing Cluster Check (using node 127.0.0.1:30001) M: 445f2a86fe36d397613839d8cc1ae6702c976593 127.0.0.1:30001 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc 127.0.0.1:30003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: e35f06ca9b700073472d72001a39ea4dfcb541cd 127.0.0.1:30006 slots: (0 slots) slave replicates 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc S: 0b17b00542706343583aa73149ec5ff63419f140 127.0.0.1:30005 slots: (0 slots) slave replicates 63bb14023c0bf58926738cbf857ea304bff8eb50 M: 63bb14023c0bf58926738cbf857ea304bff8eb50 127.0.0.1:30002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: 64828ab44566fc5ad656e831fd33de87be1387a0 127.0.0.1:30004 slots: (0 slots) slave replicates 445f2a86fe36d397613839d8cc1ae6702c976593 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. 複製程式碼
在執行的過程中會詢問你是否通過把 30001、30002、30003 作為為主節點,把 30004、30005、30006 作為它們的從節點,輸入 yes 後會執行完成。
我們可以先使用 redis-cli 連接到集群,命令如下:
$ redis-cli -c -p 30001 複製程式碼
在使用 nodes 命令來查看集群的節點資訊,命令如下:
127.0.0.1:30001> cluster nodes 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc 127.0.0.1:30003@40003 master - 0 1585125835078 3 connected 10923-16383 e35f06ca9b700073472d72001a39ea4dfcb541cd 127.0.0.1:30006@40006 slave 864d4dfe32e3e0b81a64cec8b393bbd26a65cbcc 0 1585125835078 6 connected 0b17b00542706343583aa73149ec5ff63419f140 127.0.0.1:30005@40005 slave 63bb14023c0bf58926738cbf857ea304bff8eb50 0 1585125835078 5 connected 63bb14023c0bf58926738cbf857ea304bff8eb50 127.0.0.1:30002@40002 master - 0 1585125834175 2 connected 5461-10922 445f2a86fe36d397613839d8cc1ae6702c976593 127.0.0.1:30001@40001 myself,master - 0 1585125835000 1 connected 0-5460 64828ab44566fc5ad656e831fd33de87be1387a0 127.0.0.1:30004@40004 slave 445f2a86fe36d397613839d8cc1ae6702c976593 0 1585125835000 4 connected 複製程式碼
可以看出 30001、30002、30003 都為主節點,30001 對應的槽位是 0-5460,30002 對應的槽位是 5461-10922,30003 對應的槽位是 10923-16383,總共有槽位 16384 個 (0 ~ 16383)。
create-cluster 搭建的方式雖然速度很快,但是該方式搭建的集群主從節點數量固定以及槽位分配模式固定,並且安裝在同一台伺服器上,所以只能用於測試環境。
我們測試完成之後,可以使用以下命令,關閉並清理集群:
$ ./create-cluster stop # 關閉集群 Stopping 30001 Stopping 30002 Stopping 30003 Stopping 30004 Stopping 30005 Stopping 30006 $ ./create-cluster clean # 清理集群 複製程式碼
2.手動搭建 Redis Cluster
由於 create-cluster 本身的限制,在實際生產環境中我們需要使用手動添加配置的方式搭建 Redis 集群,為此我們先要把 Redis 安裝包複製到 node1 到 node6 文件中,因為我們要安裝 6 個節點,3 主 3 從,如下圖所示:


接下來我們進行配置並啟動 Redis 集群。
① 設置配置文件
我們需要修改每個節點內的 redis.conf 文件,設置 cluster-enabled yes 表示開啟集群模式,並且修改各自的埠,我們繼續使用 30001 到 30006,通過 port 3000X 設置。
② 啟動各個節點
redis.conf 配置好之後,我們就可以啟動所有的節點了,命令如下:
cd /usr/local/soft/mycluster/node1 ./src/redis-server redis.conf 複製程式碼
③ 創建集群並分配槽位
之前我們已經啟動了 6 個節點,但這些節點都在各自的集群之內並未互聯互通,因此接下來我們需要把這些節點串連成一個集群,並為它們指定對應的槽位,執行命令如下:
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1 複製程式碼
其中 create 後面跟多個節點,表示把這些節點作為整個集群的節點,而 cluster-replicas 表示給集群中的主節點指定從節點的數量,1 表示為每個主節點設置一個從節點。
在執行了 create 命令之後,系統會為我們指定節點的角色和槽位分配計劃,如下所示:
>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:30005 to 127.0.0.1:30001 Adding replica 127.0.0.1:30006 to 127.0.0.1:30002 Adding replica 127.0.0.1:30004 to 127.0.0.1:30003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30001 slots:[0-5460] (5461 slots) master M: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30002 slots:[5461-10922] (5462 slots) master M: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30003 slots:[10923-16383] (5461 slots) master S: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30004 replicates bdd1c913f87eacbdfeabc71befd0d06c913c891c S: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30005 replicates bdd1c913f87eacbdfeabc71befd0d06c913c891c S: bdd1c913f87eacbdfeabc71befd0d06c913c891c 127.0.0.1:30006 replicates bdd1c913f87eacbdfeabc71befd0d06c913c891c Can I set the above configuration? (type 'yes' to accept): 複製程式碼
從以上資訊可以看出,Redis 打算把 30001、30002、30003 設置主節點,並為他們分配的槽位,30001 對應的槽位是 0-5460,30002 對應的槽位是 5461-10922,30003 對應的槽位是 10923-16383,並且把 30005 設置為 30001 的從節點、30006 設置為 30002 的從節點、30004 設置為 30003 的從節點,我們只需要輸入 yes 即可確認並執行分配,如下所示:
Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join .... >>> Performing Cluster Check (using node 127.0.0.1:30001) M: 887397e6fefe8ad19ea7569e99f5eb8a803e3785 127.0.0.1:30001 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: abec9f98f9c01208ba77346959bc35e8e274b6a3 127.0.0.1:30005 slots: (0 slots) slave replicates 887397e6fefe8ad19ea7569e99f5eb8a803e3785 S: 1a324d828430f61be6eaca7eb2a90728dd5049de 127.0.0.1:30004 slots: (0 slots) slave replicates f5958382af41d4e1f5b0217c1413fe19f390b55f S: dc0702625743c48c75ea935c87813c4060547cef 127.0.0.1:30006 slots: (0 slots) slave replicates 3da35c40c43b457a113b539259f17e7ed616d13d M: 3da35c40c43b457a113b539259f17e7ed616d13d 127.0.0.1:30002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: f5958382af41d4e1f5b0217c1413fe19f390b55f 127.0.0.1:30003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. 複製程式碼
顯示 OK 表示整個集群就已經成功啟動了。
接下來,我們使用 redis-cli 連接並測試一下集群的運行狀態,程式碼如下:
$ redis-cli -c -p 30001 # 連接到集群 127.0.0.1:30001> cluster info # 查看集群資訊 cluster_state:ok # 狀態正常 cluster_slots_assigned:16384 # 槽位數 cluster_slots_ok:16384 # 正常的槽位數 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 # 集群的節點數 cluster_size:3 # 集群主節點數 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_ping_sent:130 cluster_stats_messages_pong_sent:127 cluster_stats_messages_sent:257 cluster_stats_messages_ping_received:122 cluster_stats_messages_pong_received:130 cluster_stats_messages_meet_received:5 cluster_stats_messages_received:257 複製程式碼
相關欄位的說明已經標識在上述的程式碼中了,這裡就不再贅述。
動態增刪節點
某些情況下,我們需要根據實際的業務情況,對已經在運行的集群進行動態的添加或刪除節點,那我們就需要進行以下操作。
1.增加主節點
添加方式一:cluster meet
使用 cluster meet ip:port 命令就可以把一個節點加入到集群中,執行命令如下:
127.0.0.1:30001> cluster meet 127.0.0.1 30007 OK 127.0.0.1:30001> cluster nodes dc0702625743c48c75ea935c87813c4060547cef 127.0.0.1:30006@40006 slave 3da35c40c43b457a113b539259f17e7ed616d13d 0 1585142916000 6 connected df0190853a53d8e078205d0e2fa56046f20362a7 127.0.0.1:30007@40007 master - 0 1585142917740 0 connected f5958382af41d4e1f5b0217c1413fe19f390b55f 127.0.0.1:30003@40003 master - 0 1585142916738 3 connected 10923-16383 3da35c40c43b457a113b539259f17e7ed616d13d 127.0.0.1:30002@40002 master - 0 1585142913000 2 connected 5461-10922 abec9f98f9c01208ba77346959bc35e8e274b6a3 127.0.0.1:30005@40005 slave 887397e6fefe8ad19ea7569e99f5eb8a803e3785 0 1585142917000 5 connected 887397e6fefe8ad19ea7569e99f5eb8a803e3785 127.0.0.1:30001@40001 myself,master - 0 1585142915000 1 connected 0-5460 1a324d828430f61be6eaca7eb2a90728dd5049de 127.0.0.1:30004@40004 slave f5958382af41d4e1f5b0217c1413fe19f390b55f 0 1585142916000 4 connected 複製程式碼
可以看出埠為 30007 的節點並加入到集群中,並設置成了主節點。
添加方式二:add-node
使用 redis-cli --cluster add-node 添加節點ip:port 集群某節點ip:port 也可以把一個節點添加到集群中,執行命令如下:
$ redis-cli --cluster add-node 127.0.0.1:30008 127.0.0.1:30001 >>> Adding node 127.0.0.1:30008 to cluster 127.0.0.1:30001 >>> Performing Cluster Check (using node 127.0.0.1:30001) M: 887397e6fefe8ad19ea7569e99f5eb8a803e3785 127.0.0.1:30001 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: dc0702625743c48c75ea935c87813c4060547cef 127.0.0.1:30006 slots: (0 slots) slave replicates 3da35c40c43b457a113b539259f17e7ed616d13d M: df0190853a53d8e078205d0e2fa56046f20362a7 127.0.0.1:30007 slots: (0 slots) master M: f5958382af41d4e1f5b0217c1413fe19f390b55f 127.0.0.1:30003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) M: 1d09d26fd755298709efe60278457eaa09cefc26 127.0.0.1:30008 slots: (0 slots) master M: 3da35c40c43b457a113b539259f17e7ed616d13d 127.0.0.1:30002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: abec9f98f9c01208ba77346959bc35e8e274b6a3 127.0.0.1:30005 slots: (0 slots) slave replicates 887397e6fefe8ad19ea7569e99f5eb8a803e3785 S: 1a324d828430f61be6eaca7eb2a90728dd5049de 127.0.0.1:30004 slots: (0 slots) slave replicates f5958382af41d4e1f5b0217c1413fe19f390b55f [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. [ERR] Node 127.0.0.1:30008 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0. 複製程式碼
從以上結果可以看出 30008 節點也被設置成了主節點。
2.添加從節點
使用 cluster replicate nodeId 命令就可以把當前節點設置為目標節點的從節點,執行命令如下:
127.0.0.1:30008> cluster replicate df0190853a53d8e078205d0e2fa56046f20362a7 OK 127.0.0.1:30008> cluster nodes df0190853a53d8e078205d0e2fa56046f20362a7 127.0.0.1:30007@40007 master - 0 1585147827000 0 connected abec9f98f9c01208ba77346959bc35e8e274b6a3 127.0.0.1:30005@40005 slave 887397e6fefe8ad19ea7569e99f5eb8a803e3785 0 1585147827000 1 connected 1a324d828430f61be6eaca7eb2a90728dd5049de 127.0.0.1:30004@40004 slave f5958382af41d4e1f5b0217c1413fe19f390b55f 0 1585147823000 3 connected 887397e6fefe8ad19ea7569e99f5eb8a803e3785 127.0.0.1:30001@40001 master - 0 1585147826000 1 connected 0-5460 dc0702625743c48c75ea935c87813c4060547cef 127.0.0.1:30006@40006 slave 3da35c40c43b457a113b539259f17e7ed616d13d 0 1585147826930 2 connected f5958382af41d4e1f5b0217c1413fe19f390b55f 127.0.0.1:30003@40003 master - 0 1585147826000 3 connected 10923-16383 1d09d26fd755298709efe60278457eaa09cefc26 127.0.0.1:30008@40008 myself,slave df0190853a53d8e078205d0e2fa56046f20362a7 0 1585147823000 7 connected 3da35c40c43b457a113b539259f17e7ed616d13d 127.0.0.1:30002@40002 master - 0 1585147827933 2 connected 5461-10922 複製程式碼
可以看出 30008 已經變為 30007 的從節點了。
3.刪除節點
使用 cluster forget nodeId 命令就可以把一個節點從集群中移除。 此命令和 meet 命令不同的時,刪除節點需要是使用節點的 Id 進行刪除,可以通過 cluster nodes 命令查看所有節點的 Id 資訊,其中每一行的最前面的 40 位字母和數組的組合就是該節點的 Id,如下圖所示:

執行命令如下:
127.0.0.1:30001> cluster forget df0190853a53d8e078205d0e2fa56046f20362a7 OK 複製程式碼
此時我們使用 cluster nodes 命令查看集群的所有節點資訊:
127.0.0.1:30001> cluster nodes dc0702625743c48c75ea935c87813c4060547cef 127.0.0.1:30006@40006 slave 3da35c40c43b457a113b539259f17e7ed616d13d 0 1585143789940 6 connected f5958382af41d4e1f5b0217c1413fe19f390b55f 127.0.0.1:30003@40003 master - 0 1585143791000 3 connected 10923-16383 3da35c40c43b457a113b539259f17e7ed616d13d 127.0.0.1:30002@40002 master - 0 1585143789000 2 connected 5461-10922 abec9f98f9c01208ba77346959bc35e8e274b6a3 127.0.0.1:30005@40005 slave 887397e6fefe8ad19ea7569e99f5eb8a803e3785 0 1585143789000 5 connected 887397e6fefe8ad19ea7569e99f5eb8a803e3785 127.0.0.1:30001@40001 myself,master - 0 1585143786000 1 connected 0-5460 1a324d828430f61be6eaca7eb2a90728dd5049de 127.0.0.1:30004@40004 slave f5958382af41d4e1f5b0217c1413fe19f390b55f 0 1585143791945 4 connected 複製程式碼
可以看出之前的埠為 30007 的節點已經被我們成功的移除了。
小結
本文講了 Redis 集群的兩種搭建方式:create-cluster start 和 cluster create,前一種方式雖然速度比較快,但它只能創建數量固定的主從節點,並且所有節點都在同一台伺服器上,因此只能用於測試環境。我們還講了 Redis 集群動態添加主、從節點和刪除任意節點的功能。
希望本文對你有幫助,動手實踐起來吧~

