1. 程式人生 > >Redis 超詳細自動管理Cluster叢集工具上手 redis-trib.rb (多圖,手把手)

Redis 超詳細自動管理Cluster叢集工具上手 redis-trib.rb (多圖,手把手)

# 安裝介紹 ​ redis-trib.rb是一款由Redis官方提供的叢集管理工具,能夠大量減少叢集搭建的時間。 ​ 除此之外,還能夠簡化叢集的檢查、槽遷徙、負載均衡等常見的運維操作,但是使用前必須要安裝ruby環境。 ​ 1)使用yum進行安裝ruby: ``` yum install -y rubygems ``` ​ 2)預設的ruby包管理工具映象源在國外,將國外源刪除新增國內源 ``` gem sources --remove https://rubygems.org/ gem sources -a http://mirrors.aliyun.com/rubygems/ gem update --system ``` ​ 3)使用ruby的包管理工具下載必備依賴包,由於我使用的是6.2.1的Redis,可能沒有最新的,就下載一個老版本的Redis驅動,經測試沒有任何問題: ``` gem install redis -v 3.3.5 ``` ​ 另外,在新版Redis中,redis-trib.rb工具的功能都被整合在了redis-cli裡,但依然需要ruby環境 # 搭建前戲 ## 地址規劃 ​ 首先我們準備2主2從的3臺多例項伺服器,利用redis-trib.rb工具搭建1個6節點3分片的叢集(叢集最少6節點)。 ​ 然後再使用redis-trib.rb工具增加1臺多例項伺服器,組成8節點4分片的叢集。 ​ 之後再使用redis-trib.rb工具下線1臺多例項伺服器,變為6節點3分片的叢集。 ​ 地址規劃與架構圖如下: ![image-20210402153934049](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402153934049.png) 在每個節點hosts檔案中加入以下內容; ``` $ vim /etc/hosts 192.168.0.120 node1 192.168.0.130 node2 192.168.0.140 node3 192.168.0.150 node4 ``` ​ !由於該工具具有難以發現的小bug,必定出現以下問題: - 主從關係自動構建不準確,需要手動重新搭建主從關係,如果主從構建不合理,一旦發生災難情況後果不堪設想 ## 叢集準備 為所有節點下載Redis: ``` $ cd ~ $ wget https://download.redis.io/releases/redis-6.2.1.tar.gz ``` 為所有節點配置目錄: ``` $ mkdir -p /usr/local/redis_cluster/redis_63{79,80}/{conf,pid,logs} ``` 所有節點進行解壓: ``` $ tar -zxvf redis-6.2.1.tar.gz -C /usr/local/redis_cluster/ ``` 所有節點進行編譯安裝Redis: ``` $ cd /usr/local/redis_cluster/redis-6.2.1/ $ make && make install ``` 書寫叢集配置檔案,注意!Redis普通服務會有2套配置檔案,一套為普通服務配置檔案,一套為叢集服務配置檔案,我們這裡是做的叢集,所以書寫的叢集配置檔案,共6份: ``` $ vim /usr/local/redis_cluster/redis_6379/conf/redis.cnf # 快速修改::%s/6379/6380/g # 守護進行模式啟動 daemonize yes # 設定資料庫數量,預設資料庫為0 databases 16 # 繫結地址,需要修改 bind 192.168.0.120 # 繫結埠,需要修改 port 6379 # pid檔案儲存位置,檔名需要修改 pidfile /usr/local/redis_cluster/redis_6379/pid/redis_6379.pid # log檔案儲存位置,檔名需要修改 logfile /usr/local/redis_cluster/redis_6379/logs/redis_6379.log # RDB快照備份檔名,檔名需要修改 dbfilename redis_6379.rdb # 本地資料庫儲存目錄,需要修改 dir /usr/local/redis_cluster/redis_6379 # 叢集相關配置 # 是否以叢集模式啟動 cluster-enabled yes # 叢集節點回應最長時間,超過該時間被認為下線 cluster-node-timeout 15000 # 生成的叢集節點配置檔名,檔名需要修改 cluster-config-file nodes_6379.conf ``` # 叢集搭建 ## 啟動叢集 ​ 每個節點上執行以下2條命令進行服務啟動: ``` $ redis-server /usr/local/redis_cluster/redis_6379/conf/redis.cnf $ redis-server /usr/local/redis_cluster/redis_6380/conf/redis.cnf ``` ​ 叢集模式啟動,它的程序後會加上[cluster]的字樣: ``` $ ps -ef | grep redis root 78586 1 0 21:56 ? 00:00:00 redis-server 192.168.0.120:6379 [cluster] root 78616 1 0 21:56 ? 00:00:00 redis-server 192.168.0.120:6380 [cluster] root 78636 71501 0 21:56 pts/1 00:00:00 grep --color=auto redis ``` ​ 同時,檢視一下叢集節點配置檔案,會發現生成了一組叢集資訊,每個Redis服務都是不同的: ``` $ cat /usr/local/redis_cluster/redis_6379/nodes_6379.conf c71b52f728ab58fedb6e05a525ce00b453fd2f6b :0@0 myself,master - 0 0 0 connected vars currentEpoch 0 lastVoteEpoch 0 $ cat /usr/local/redis_cluster/redis_6380/nodes_6380.conf d645d06708e1eddb126a6c3c4e38810c188d0906 :0@0 myself,master - 0 0 0 connected vars currentEpoch 0 lastVoteEpoch 0 # 第一段資訊是這個Redis服務作為叢集節點的一個身份編碼 # 別名為叢集的node-id ``` ## 自動化 ​ 現在我們有2個部分還沒有做,1是對叢集進行分槽工作,2是構建主從關係。 ​ 通過redis-trib.rb工具,這個步驟將變得異常簡單,由於我的ruby是裝在node1上,所以只需要在node1執行下面一句話即可。 ``` $ cd /usr/local/redis_cluster/redis-6.2.1/src/ # 舊版Redis這裡以指令碼名開頭 redis-trib.rb 跟上後面引數即可 $ redis-cli --cluster create 192.168.0.120:6379 192.168.0.140:6380 192.168.0.130:6379 192.168.0.120:6380 192.168.0.140:6379 192.168.0.130:6380 --cluster-replicas 1 ``` ​ 引數釋義: - --cluster-replicas:指定的副本數,其實這一條命令的語法規則是如果副本數為1,第一個ip:port與它後面的1個ip:port建立1主1從關係,如果副本數是2,第一個ip:port與它後面的2個ip:port建立1主2從關係,以此類推 ​ 執行完這條命令後,輸入yes,會看到以下資訊: ``` $ redis-cli --cluster create 192.168.0.120:6379 192.168.0.140:6380 192.168.0.130:6379 192.168.0.120:6380 192.168.0.140:6379 192.168.0.130:6380 --cluster-replicas 1 # 主從相關 >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.0.140:6379 to 192.168.0.120:6379 Adding replica 192.168.0.130:6380 to 192.168.0.140:6380 Adding replica 192.168.0.120:6380 to 192.168.0.130:6379 M: c71b52f728ab58fedb6e05a525ce00b453fd2f6b 192.168.0.120:6379 slots:[0-5460] (5461 slots) master M: 6a627cedaa4576b1580806ae0094be59c32fa391 192.168.0.140:6380 slots:[5461-10922] (5462 slots) master M: 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 192.168.0.130:6379 slots:[10923-16383] (5461 slots) master S: d645d06708e1eddb126a6c3c4e38810c188d0906 192.168.0.120:6380 replicates 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f S: 7a7392cb66bea30da401d2cb9768a42bbdefc5db 192.168.0.140:6379 replicates c71b52f728ab58fedb6e05a525ce00b453fd2f6b S: ff53e43f9404981a51d4e744de38004a5c22b090 192.168.0.130:6380 replicates 6a627cedaa4576b1580806ae0094be59c32fa391 # 詢問是否儲存配置?輸入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 192.168.0.120:6379) M: c71b52f728ab58fedb6e05a525ce00b453fd2f6b 192.168.0.120:6379 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 192.168.0.130:6379 slots:[10923-16383] (5461 slots) master 1 additional replica(s) M: 6a627cedaa4576b1580806ae0094be59c32fa391 192.168.0.140:6380 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: d645d06708e1eddb126a6c3c4e38810c188d0906 192.168.0.120:6380 slots: (0 slots) slave replicates 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f S: 7a7392cb66bea30da401d2cb9768a42bbdefc5db 192.168.0.140:6379 slots: (0 slots) slave replicates c71b52f728ab58fedb6e05a525ce00b453fd2f6b S: ff53e43f9404981a51d4e744de38004a5c22b090 192.168.0.130:6380 slots: (0 slots) slave replicates 6a627cedaa4576b1580806ae0094be59c32fa391 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. $ ``` ​ 仔細觀察上面的主從關係就可以看到異常,我的規劃是所有的6379為主節點,而6380為從節點,顯然他沒有按照我的意思進行劃分主從。 ​ 這種情況還算好的,至少不同節點都是岔開的,怕就怕一臺機器2個例項組成1主1從,如果是那樣的結構主從就沒有任何意義。 ![image-20210402113618358](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402113618358.png) ​ ## 主從校正 ​ 由於上面自動部署時主從關係出現了問題,超乎了我們的預期(這可能是該工具的bug),所以我們要對其進行手動校正。 ​ 1)登入node3:6380,讓其作為node1:6379的從庫,由於node3:6380是一個主庫,要想變為從庫必須先清空它的插槽,而後進行指定: ``` $ redis-cli -h node3 -p 6380 -c node3:6380> CLUSTER FLUSHSLOTS node3:6380> CLUSTER REPLICATE c71b52f728ab58fedb6e05a525ce00b453fd2f6b ``` ![image-20210402112159652](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402112159652.png) ​ 2)登入node3:6379,讓該庫進行下線,此舉是為了重新上線令其角色變為master: ``` $ redis-cli -h node3 -p 6379 -c node3:6379> CLUSTER RESET ``` ![image-20210402155206565](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402155206565.png) ​ ​ 3)登入node1:6379(其實任意叢集中的一個都行)重新發現node3:6379,並且記錄下缺失的插槽資訊: ``` $ redis-cli -h node1 -p 6379 -c node1:6379> CLUSTER MEET 192.168.0.140 6379 node1:6379> CLUSTER NODES # 僅關注master最後這一部分資訊,槽位 connected 10923-16383 connected 0-5460 # 已分配10923-16383、0-5460,缺失的插槽位為5461-10922 ``` ![image-20210402155330248](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402155330248.png) ​ ​ 4)為node3:6379分配插槽: ``` $ redis-cli -h node3 -p 6379 cluster addslots {5461..10922} ``` ![image-20210402155400594](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402155400594.png) ​ 5)登入node2:6380,讓其對應node3:6379,即前者作為後者的從庫 ``` $ redis-cli -h node2 -p 6380 node2:6380> CLUSTER REPLICATE 7a7392cb66bea30da401d2cb9768a42bbdefc5db ``` ![image-20210402155436436](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402155436436.png) ​ 6)檢視叢集是否是成功執行的狀態: ``` node2:6380> 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:12 cluster_my_epoch:12 cluster_stats_messages_ping_sent:4406 cluster_stats_messages_pong_sent:4225 cluster_stats_messages_meet_sent:1 cluster_stats_messages_sent:8632 cluster_stats_messages_ping_received:4225 cluster_stats_messages_pong_received:4413 cluster_stats_messages_auth-req_received:4 cluster_stats_messages_received:8642 ``` ​ 7)檢查各個節點關係之間是否正常: ``` node2:6380> CLUSTER NODES d645d06708e1eddb126a6c3c4e38810c188d0906 192.168.0.120:6380@16380 slave 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 0 1617335179000 3 connected 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 192.168.0.130:6379@16379 master - 0 1617335177627 3 connected 10923-16383 ff53e43f9404981a51d4e744de38004a5c22b090 192.168.0.130:6380@16380 myself,slave 7a7392cb66bea30da401d2cb9768a42bbdefc5db 0 1617335178000 12 connected 7a7392cb66bea30da401d2cb9768a42bbdefc5db 192.168.0.140:6379@16379 master - 0 1617335180649 12 connected 5461-10922 c71b52f728ab58fedb6e05a525ce00b453fd2f6b 192.168.0.120:6379@16379 master - 0 1617335179000 12 connected 0-5460 6a627cedaa4576b1580806ae0094be59c32fa391 192.168.0.140:6380@16380 slave 7a7392cb66bea30da401d2cb9768a42bbdefc5db 0 1617335179644 12 connected ``` ​ ​ 下面可能是我上面操作時輸錯了node-id導致的,一般按正確步驟來說不用產生這種情況。 ​ \*8)發現節點關係還是不正常,node3:6380也對應了node3:6379,更改一下就好了,讓其對應node1的6379: ``` $ redis-cli -h node3 -p 6380 node3:6380> CLUSTER REPLICATE c71b52f728ab58fedb6e05a525ce00b453fd2f6b ``` ​ *9)再次檢查,節點關係正常: ``` node3:6380> CLUSTER NODES c71b52f728ab58fedb6e05a525ce00b453fd2f6b 192.168.0.120:6379@16379 master - 0 1617335489929 12 connected 0-5460 6a627cedaa4576b1580806ae0094be59c32fa391 192.168.0.140:6380@16380 myself,slave c71b52f728ab58fedb6e05a525ce00b453fd2f6b 0 1617335490000 12 connected 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 192.168.0.130:6379@16379 master - 0 1617335487913 3 connected 10923-16383 d645d06708e1eddb126a6c3c4e38810c188d0906 192.168.0.120:6380@16380 slave 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 0 1617335488000 3 connected 7a7392cb66bea30da401d2cb9768a42bbdefc5db 192.168.0.140:6379@16379 master - 0 1617335489000 12 connected 5461-10922 ff53e43f9404981a51d4e744de38004a5c22b090 192.168.0.130:6380@16380 slave 7a7392cb66bea30da401d2cb9768a42bbdefc5db 0 1617335490931 12 connected node3:6380> ``` # 叢集擴容 ## 發現節點 ​ 現在我們的node4還沒有新增進叢集,所以將node4進行新增: ``` $ redis-cli -h node1 -p 6379 CLUSTER MEET 192.168.0.150 6379 $ redis-cli -h node1 -p 6379 CLUSTER MEET 192.168.0.150 6380 ``` ​ 檢視節點資訊,對內容進行部分擷取: ``` $ redis-cli -h node1 -p 6379 node3:6380> cluster nodes # 這裡 f3dec547054791b01cfa9431a4c7a94e62f81db3 192.168.0.150:6380@16380 master - 0 1617337335000 0 connected d1ca7e72126934ef569c4f4d34ba75562d36068f 192.168.0.150:6379@16379 master - 0 1617337337289 14 connected ``` ​ 目前node4的6379和6380並未建立槽位,也沒有和其他節點建立聯絡,所以不能進行任何讀寫操作。 ## 進行擴容 ​ 使用redis-trib.rb工具對新節點進行擴容,大體流程是每個節點拿出一部分槽位分配給node4:6379。 ![image-20210402161015475](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402161015475.png) ​ 在槽位遷徙時會帶著資料一起遷徙,這並不會影響正常業務,屬於熱擴容。 ​ 首先要做4分片的規劃,每個節點共分4096個槽位: ``` $ python3 >>> divmod(16384,4) (4096, 0) ``` ​ 接下來開始進行擴容,由於我們只在node1上裝了ruby環境,所以在node1上執行: ``` $ cd /usr/local/redis_cluster/redis-6.2.1/src/ # 舊版Redis這裡以指令碼名開頭 redis-trib.rb,並且不需要新增--cluster引數 $ redis-cli --cluster reshard 192.168.0.120 6379 # 你需要分配多少? How many slots do you want to move (from 1 to 16384)? 4096 # 你要給哪一個叢集節點分配插槽?我是給node4節點的6379 what is the receiving node ID? d1ca7e72126934ef569c4f4d34ba75562d36068f # 你要從哪些叢集節點給node4節點6379分配插槽呢?可以輸入all代表所有節點平均分配 # 也可以輸入所有節點node-ID以done結束,我這裡是所有節點,需要node1:6379、node2:6379、node3:6379 # 共拿出4096的槽位分配給node4:6379 Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1: all ``` ​ 經過漫長的等待,終於擴容完成了: ``` $ redis-cli -h node1 -p 6379 cluster nodes 192.168.0.150:6379@16379 master - 0 1617337961000 14 connected 0-1364 5461-6826 10923-12287 192.168.0.130:6379@16379 master - 0 1617337967569 3 connected 12288-16383 192.168.0.120:6379@16379 myself,master - 0 1617337967000 12 connected 1365-5460 192.168.0.140:6379@16379 master - 0 1617337963000 13 connected 6827-10922 ``` ​ 檢視叢集節點資訊,發現他分配的並不是特別均勻,只要誤差在2%以內,就算正常範圍。 ## 主從修改 ​ 如果你在線上生產環境中對Redis叢集進行了擴容,一定要注意主從關係。 ​ 手動的對主從關係進行校正,這裡不再進行演示。 # 叢集縮容 ## 移除節點 ​ 下線節點時,節點如果持有槽必須指定將該槽遷徙到別的節點。 ​ 在槽遷徙時,資料也會一併遷徙,並不影響業務。 ![image-20210402123903685](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402123903685.png) ​ 同時,當槽遷徙完成後,可在叢集中對該節點進行遺忘。 ## 進行縮容 ​ 這裡縮容物件還是node4:6379,它本身具有4096個插槽,我們需要分別把4096個插槽移動到node1:6379、node2:6379、node3:6379上。 ![image-20210402161216191](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210402161216191.png) 計算每個節點分多少: ``` $ python3 >>> divmod(4096,3) (1365, 1) # 2個分1365 1個分1366 ``` ​ 開始縮容,以下操作做3次: ``` $ cd /usr/local/redis_cluster/redis-6.2.1/src/ # 舊版Redis這裡以指令碼名開頭 redis-trib.rb,並且不需要新增--cluster引數 $ redis-cli --cluster reshard 192.168.0.120 6379 >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. # 你想移動多少插槽?2次1365,1次1366 How many slots do you want to move (from 1 to 16384)? 1365 # 你想由誰來接收? node1:6379、node2:6379、node3:6379的node-id What is the receiving node ID? 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f # 你想指定那個節點發送插槽? Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. # node4:6379的node-id Source node #1: d1ca7e72126934ef569c4f4d34ba75562d36068f Source node #2: done # 輸入yes Do you want to proceed with the proposed reshard plan (yes/no)? yes ``` ​ 擴容完成後檢查叢集狀態: ``` $ redis-cli -h node1 -p 6379 cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:8 cluster_size:3 cluster_current_epoch:17 cluster_my_epoch:15 cluster_stats_messages_ping_sent:17672 cluster_stats_messages_pong_sent:26859 cluster_stats_messages_meet_sent:7 cluster_stats_messages_auth-req_sent:10 cluster_stats_messages_auth-ack_sent:2 cluster_stats_messages_update_sent:23 cluster_stats_messages_mfstart_sent:1 cluster_stats_messages_sent:44574 cluster_stats_messages_ping_received:17283 cluster_stats_messages_pong_received:24508 cluster_stats_messages_meet_received:5 cluster_stats_messages_fail_received:1 cluster_stats_messages_auth-req_received:2 cluster_stats_messages_auth-ack_received:5 cluster_stats_messages_mfstart_received:1 cluster_stats_messages_received:41805 ``` ​ 檢視node4:6379是否有未分配出去的插槽: ``` $ redis-cli -h node1 -p 6379 cluster nodes # 沒有佔據任何槽位、已被全部分配出去 d1ca7e72126934ef569c4f4d34ba75562d36068f 192.168.0.150:6379@16379 master - 0 1617349187107 14 connected f3dec547054791b01cfa9431a4c7a94e62f81db3 192.168.0.150:6380@16380 master - 0 1617349182874 0 connected ``` ## 進行下線 ​ 現在就可以對node4:6379與node4:6380進行下線了,任意登入叢集中某一節點,輸入以下命令: ``` $ redis-cli -h node1 -p 6379 cluster FORGET d1ca7e72126934ef569c4f4d34ba75562d36068f $ redis-cli -h node1 -p 6379 cluster FORGET f3dec547054791b01cfa9431a4c7a94e62f81db3 ``` ​ 檢查是否以從節點中移除: ``` $ redis-cli -h node1 -p 6379 cluster nodes ff53e43f9404981a51d4e744de38004a5c22b090 192.168.0.130:6380@16380 slave 7a7392cb66bea30da401d2cb9768a42bbdefc5db 0 1617349417000 17 connected d645d06708e1eddb126a6c3c4e38810c188d0906 192.168.0.120:6380@16380 slave 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 0 1617349415310 16 connected 282358c2fb0c7c16ec60f2c4043b52a0eb91e19f 192.168.0.130:6379@16379 master - 0 1617349414244 16 connected 5461-6825 12288-16383 c71b52f728ab58fedb6e05a525ce00b453fd2f6b 192.168.0.120:6379@16379 myself,master - 0 1617349414000 15 connected 0-5460 7a7392cb66bea30da401d2cb9768a42bbdefc5db 192.168.0.140:6379@16379 master - 0 1617349416000 17 connected 6826-12287 6a627cedaa4576b1580806ae0094be59c32fa391 192.168.0.140:6380@16380 slave c71b52f728ab58fedb6e05a525ce00b453fd2f6b 0 1617349417761 15 connected ``` ​ 至此,node4:6379以及node4:6380成功下線。 ## 主從修改 ​ 如果你在線上生產環境中對Redis叢集進行縮容,一定要注意主從關係。 ​ 手動的對主從關係進行校正,這裡不再進行演示。