Redis進階實踐之十三 Redis的Redis-trib.rb腳本文件使用詳解


一、簡介

      事先說明一下,本篇文章不涉及對redis-trib.rb源代碼的分析,只是從使用的角度來闡述一下,對第一次使用的人來說很重要。redis-trib.rb是redis官方推出的管理redis集群的工具,集成在redis的源碼src目錄下,是基於redis提供的集群命令封裝成簡單、便捷、實用的操作工具。這個文件可以在src這個目錄下使用,也可以像redis-cli等命令一樣,可以拷貝到單獨目錄,方便使用。redis-trib.rb是redis作者用ruby寫成的,為了看懂redis-trib.rb的源碼,我還要花一些時間來學學ruby。ruby這門語言我是在老趙的教程里面最早聽說的,認為這個語言和我關系不大,當初也就沒有在意,自然也就沒學了。現在看來不行了,所以我就特意花了一個月的時間學習了一下ruby這門語言,同時也被ruby語言的簡潔、明了所吸引。閱讀本文需要對redis集群功能有一定的了解。關於redis集群功能的介紹,可以參考本人的另兩篇文章,第一篇是《Redis進階實踐之十一 Redis的Cluster集群搭建》,第二篇是《Redis進階實踐之十二 Redis的Cluster集群動態擴容》。


二、Redis-trib.rb詳細介紹

        Redis-Trib.rb這個腳本文件的功能很強大,使用起來也很方便,我們就由淺入深來探討這個腳本文件的使用吧。我們先來看看他的幫助信息吧,這個最簡單,學習一門新技術的時候,也應該先看看幫助的東西。

   1、#ruby redis-trib.rb help (Redis-Trib.rb的幫助信息)
 2 
 3         [root@linux redis]# ruby redis-trib.rb help
 4         Usage: redis-trib <command> <options> <arguments ...>
 5 
 6           create          host1:port1 ... hostN:portN
 7                           --replicas <arg>
 8           check           host:port
 9           info            host:port
10           fix             host:port
11                           --timeout <arg>
12           reshard         host:port
13                           --from <arg>
14                           --to <arg>
15                           --slots <arg>
16                           --yes
17                           --timeout <arg>
18                           --pipeline <arg>
19           rebalance       host:port
20                           --weight <arg>
21                           --auto-weights
22                           --use-empty-masters
23                           --timeout <arg>
24                           --simulate
25                           --pipeline <arg>
26                           --threshold <arg>
27           add-node        new_host:new_port existing_host:existing_port
28                           --slave
29                           --master-id <arg>
30           del-node        host:port node_id
31           set-timeout     host:port milliseconds
32           call            host:port command arg arg .. arg
33           import          host:port
34                           --from <arg>
35                           --copy
36                           --replace
37           help            (show this help)
38     
39         For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.


      (對於check,fix,reshard,del-node,settimeout,你可以指定集群中任何工作節點的主機和端口。)

            可以看到redis-trib.rb具有以下功能:

              1、create:創建集群

              2、check:檢查集群

              3、info:查看集群信息

              4、fix:修復集群

              5、reshard:在線遷移slot

              6、rebalance:平衡集群節點slot數量

              7、add-node:將新節點加入集群

              8、del-node:從集群中刪除節點

              9、set-timeout:設置集群節點間心跳連接的超時時間

              10、call:在集群全部節點上執行命令

              11、import:將外部redis數據導入集群


      2、Create創建集群

            命令格式:ruby redis-trib.rb  create  [--replicas <arg>]  host1:port1 ... hostN:portN【地址列表必須大於等於3】

            replicas參數是可選參數,表示每個Master主節點有幾個slave從節點,如果該參數存在,必須在 host1:port1 ... hostN:portN 之前,如果省略了[--replicas <arg>]這個參數,只會創建最少3個Master主節點(因為Redis的Cluster集群模式要求最少3個主節點),並且分配好數據槽slots,但是,Slave從節點是不會創建的。

            Master主節點沒有Slave從節點,最簡單命令使用如下:

        [root@linux redis]# ruby redis-trib.rb create 192.168.127.129:7000 192.168.127.129:7001 192.168.127.129:7002
        >>> Creating cluster
        >>> Performing hash slots allocation on 3 nodes...
        Using 3 masters:
        192.168.127.129:7000
        192.168.127.129:7001
        192.168.127.129:7002
        M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
           slots:0-5460 (5461 slots) master
        M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
           slots:5461-10922 (5462 slots) master
        M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
           slots:10923-16383 (5461 slots) master
        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.127.129:7000)
        M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
           slots:0-5460 (5461 slots) master
           0 additional replica(s)
        M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
           slots:5461-10922 (5462 slots) master
           0 additional replica(s)
        M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
           slots:10923-16383 (5461 slots) master
           0 additional replica(s)
        [OK] All nodes agree about slots configuration.
        >>> Check for open slots...
        >>> Check slots coverage...
        [OK] All 16384 slots covered.


            每個Master主節點都有一個slave從節點的創建命令如下:
            [root@linux redis]# ruby redis-trib.rb create --replicas 1 192.168.127.130:7000 192.168.127.130:7001  192.168.127.130:7002 192.168.127.130:7003 192.168.127.130:7004 192.168.127.130:7005

            創建流程如下:

                   1、首先為每個節點創建ClusterNode對象,包括連接每個節點。檢查每個節點是否為獨立且db為空的節點。執行load_info方法導入節點信息。

                   2、檢查傳入的master節點數量是否大於等於3個。只有大於3個節點才能組成集群。

                   3、計算每個master需要分配的slot數量,以及給master分配slave。

                   4、打印出分配信息,並提示用戶輸入“yes”確認是否按照打印出來的分配方式創建集群。

                   5、輸入“yes”后,會執行flush_nodes_config操作,該操作執行前面的分配結果,給master分配slot,讓slave復制master,對於還沒有握手(cluster meet)的節點,slave復制操作無法完成,不過沒關系,flush_nodes_config操作出現異常會很快返回,后續握手后會再次執行flush_nodes_config。

                   6、給每個節點分配epoch,遍歷節點,每個節點分配的epoch比之前節點大1。

                   7、節點間開始相互握手,握手的方式為節點列表的其他節點跟第一個節點握手。

                   8、然后每隔1秒檢查一次各個節點是否已經消息同步完成,使用ClusterNode的get_config_signature方法,檢查的算法為獲取每個節點cluster nodes信息,排序每個節點,組裝成node_id1:slots|node_id2:slot2|...的字符串。如果每個節點獲得字符串都相同,即認為握手成功。

                   9、此后會再執行一次flush_nodes_config,這次主要是為了完成slave復制操作。

                      10、最后再執行check_cluster,全面檢查一次集群狀態。包括和前面握手時檢查一樣的方式再檢查一遍。確認沒有遷移的節點。確認所有的slot都被分配出去了。

                   11、至此完成了整個創建流程,返回[OK] All 16384 slots covered.。


      3、Check檢查集群主從狀態信息

            命令格式:ruby redis-trib.rb  check  host:port【此地址可以是集群中任何一個節點的地址,相當於獲取集群信息的入口】

            檢查集群狀態的命令,沒有其他參數,只需要選擇一個集群中的一個節點即可。執行命令以及結果如下:

            [root@linux redis]# ruby redis-trib.rb check 192.168.127.130:7000
            >>> Performing Cluster Check (using node 192.168.127.130:7000)
            M: a44081c39e7978c731a5c64476f4dc64e8d10c20 192.168.127.130:7000
               slots:66-5460 (5395 slots) master
               1 additional replica(s)
            S: be14cfa7cc064e75977ec8517c1eccf96e92aebf 192.168.127.130:7005
               slots: (0 slots) slave
               replicates 3b025b3ecfa65f462de639c7a412be443cf1dd1c
            M: bafe517c084aadaacb0b0249dac1e706f24bc21f 192.168.127.130:7001
               slots:5528-10922 (5395 slots) master
               1 additional replica(s)
            S: b04d39427329b256fcb9b851e02d4b814314b280 192.168.127.130:7004
               slots: (0 slots) slave
               replicates bafe517c084aadaacb0b0249dac1e706f24bc21f
            M: 3b025b3ecfa65f462de639c7a412be443cf1dd1c 192.168.127.130:7002
               slots:0-65,5461-5527,10923-16383 (5594 slots) master
               1 additional replica(s)
            S: b96aac031170a2aa42c619fbc08450bb51af372c 192.168.127.130:7003
               slots: (0 slots) slave
               replicates a44081c39e7978c731a5c64476f4dc64e8d10c20
            [OK] All nodes agree about slots configuration.
            >>> Check for open slots...
            >>> Check slots coverage...
              [OK] All 16384 slots covered.


            檢查前會先執行load_cluster_info_from_node方法,把所有節點數據load進來。load的方式為通過自己的cluster nodes發現其他節點,然后連接每個節點,並加入nodes數組。接着生成節點間的復制關系。load完數據后,開始檢查數據,檢查的方式也是調用創建時候使用的check_cluster。


      4、Info查看集群主節點信息

            命令格式:ruby redis-trib.rb  info  host:port【此地址可以是集群中任何一個節點的地址,相當於獲取集群信息的入口】

            info命令用來查看集群中Master主節點的信息。info命令也是先執行load_cluster_info_from_node獲取完整的集群信息。

            示例如下:

       [root@linux redis]# ruby redis-trib.rb info 192.168.127.130:7000
          192.168.127.130:7000 (a44081c3...) -> 3 keys | 5395 slots | 1 slaves.
          192.168.127.130:7001 (bafe517c...) -> 1 keys | 5395 slots | 1 slaves.
          192.168.127.130:7002 (3b025b3e...) -> 1 keys | 5594 slots | 1 slaves.
          [OK] 5 keys in 3 masters.
          0.00 keys per slot on average.



      5、Fix修復集群

            命令格式:ruby redis-trib.rb  fix  --timeout <arg>  host:port【此地址可以是集群中任何一個節點的地址,相當於獲取集群信息的入口】

            執行效果如下:

       [root@linux redis]# ruby redis-trib.rb fix 192.168.127.130:7002
          >>> Performing Cluster Check (using node 192.168.127.130:7002)
          M: 3b025b3ecfa65f462de639c7a412be443cf1dd1c 192.168.127.130:7002
             slots:0-65,5461-5527,10923-16383 (5594 slots) master
             1 additional replica(s)
          M: bafe517c084aadaacb0b0249dac1e706f24bc21f 192.168.127.130:7001
             slots:5528-10922 (5395 slots) master
             1 additional replica(s)
            S: b96aac031170a2aa42c619fbc08450bb51af372c 192.168.127.130:7003
             slots: (0 slots) slave
             replicates a44081c39e7978c731a5c64476f4dc64e8d10c20
          S: b04d39427329b256fcb9b851e02d4b814314b280 192.168.127.130:7004
             slots: (0 slots) slave
             replicates bafe517c084aadaacb0b0249dac1e706f24bc21f
          M: a44081c39e7978c731a5c64476f4dc64e8d10c20 192.168.127.130:7000
             slots:66-5460 (5395 slots) master
             1 additional replica(s)
          S: be14cfa7cc064e75977ec8517c1eccf96e92aebf 192.168.127.130:7005
             slots: (0 slots) slave
             replicates 3b025b3ecfa65f462de639c7a412be443cf1dd1c
          [OK] All nodes agree about slots configuration.
          >>> Check for open slots...
          >>> Check slots coverage...
          [OK] All 16384 slots covered.

          [root@linux redis]# ruby redis-trib.rb fix 192.168.127.130:7005
          >>> Performing Cluster Check (using node 192.168.127.130:7005)
          S: be14cfa7cc064e75977ec8517c1eccf96e92aebf 192.168.127.130:7005
             slots: (0 slots) slave
             replicates 3b025b3ecfa65f462de639c7a412be443cf1dd1c
          S: b96aac031170a2aa42c619fbc08450bb51af372c 192.168.127.130:7003
             slots: (0 slots) slave
             replicates a44081c39e7978c731a5c64476f4dc64e8d10c20
          M: 3b025b3ecfa65f462de639c7a412be443cf1dd1c 192.168.127.130:7002
             slots:0-65,5461-5527,10923-16383 (5594 slots) master
             1 additional replica(s)
          M: a44081c39e7978c731a5c64476f4dc64e8d10c20 192.168.127.130:7000
             slots:66-5460 (5395 slots) master
             1 additional replica(s)
          S: b04d39427329b256fcb9b851e02d4b814314b280 192.168.127.130:7004
             slots: (0 slots) slave
             replicates bafe517c084aadaacb0b0249dac1e706f24bc21f
          M: bafe517c084aadaacb0b0249dac1e706f24bc21f 192.168.127.130:7001
             slots:5528-10922 (5395 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.


            1、fix命令的流程跟check的流程很像,顯示加載集群信息,然后在check_cluster方法內傳入fix為
true的變量,會在集群檢查出現異常的時候執行修復流程。目前fix命令能修復兩種異常,一種是集群有處於遷移中的slot的節點,一種是slot未完全分配的異常。

            2、fix_open_slot方法是修復集群中在遷移slots數據槽的過程中節點的異常。

                  2.1、先檢查該slot是誰負責的,遷移的源節點如果沒完成遷移,owner還是該節點。沒有owner的slot無法完成修復功能。

                  2.2、遍歷每個節點,獲取哪些節點的slot被標記為migrating【遷移】狀態,哪些節點的slot被標記為importing【輸入】狀態。對於owner【所有者】不是該節點,但是通過cluster countkeysinslot獲取到該節點有數據的情況,也認為該節點為importing【輸入】狀態。

                  2.3、如果migrating【遷移】和importing【輸入】狀態的節點均只有1個,這可能是遷移過程中redis-trib.rb被中斷所致,直接執行move_slot繼續完成遷移任務即可。傳遞dots和fix為true。

                  2.4、如果migrating【遷移】為空,importing【輸入】狀態的節點大於0,那么這種情況執行回滾流程,將importing【輸入】狀態的節點數據通過move_slot方法導給slot的owner【所有者】節點,傳遞dots、fix和cold為true。接着對importing的節點執行cluster stable命令恢復穩定。

                  2.5、如果importing【輸入】狀態的節點為空,有一個migrating【遷移】狀態的節點,而且該節點在當前slot沒有數據,那么可以直接把這個slot設為stable。

                  2.6、如果migrating【遷移】和importing【輸入】狀態不是上述情況,目前redis-trib.rb工具無法修復,上述的三種情況也已經覆蓋了通過redis-trib.rb工具遷移出現異常的各個方面,人為的異常情形太多,很難考慮完全。


            3、fix_slots_coverage方法能修復slot未完全分配的異常。未分配的slot有三種狀態。

                  3.1、所有節點的該slot都沒有數據。該狀態redis-trib.rb工具直接采用隨機分配的方式,並沒有考慮節點的均衡。本人嘗試對沒有分配slot的集群通過fix修復集群,結果slot還是能比較平均的分配,但是沒有了連續性,打印的slot信息非常離散。
    
                  3.2、有一個節點的該slot有數據。該狀態下,直接把slot分配給該slot有數據的節點。

                  3.3、有多個節點的該slot有數據。此種情況目前還處於TODO狀態,不過redis作者列出了修復的步驟,對這些節點,除第一個節點,執行cluster migrating命令,然后把這些節點的數據遷移到第一個節點上。清除migrating狀態,然后把slot分配給第一個節點。


       6、Reshard在線遷移slot

              命令格式:ruby redis-trib.rb  reshard  --from <arg>  host:port【此地址可以是集群中任何一個主節點的地址,相當於獲取集群信息的入口】
                                                        --to <arg>
                                                        --slots <arg>
                                                          --yes
                                                          --timeout <arg>
                                                          --pipeline <arg>


              reshard命令可以在線把集群的一些slot從集群原來slot負責節點遷移到新的節點,利用reshard可以完成集群的在線橫向擴容和縮容。

              reshard的參數很多,下面來一一解釋一番:
                          
              host:port:這個是必傳參數,用來從一個節點獲取整個集群信息,相當於獲取集群信息的入口。

              --from <arg>:需要從哪些源節點上遷移slot,可從多個源節點完成遷移,以逗號隔開,傳遞的是節點的node id,還可以直接傳遞--from all,這樣源節點就是集群的所有節點,不傳遞該參數的話,則會在遷移過程中提示用戶輸入。

              --to <arg>:slot需要遷移的目的節點的node id,目的節點只能填寫一個,不傳遞該參數的話,則會在遷移過程中提示用戶輸入。

              --slots <arg>:需要遷移的slot數量,不傳遞該參數的話,則會在遷移過程中提示用戶輸入。

              --yes:設置該參數,可以在打印執行reshard計划的時候,提示用戶輸入yes確認后再執行reshard。

              --timeout <arg>:設置migrate命令的超時時間。

              --pipeline <arg>:定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值為10。

           執行代碼實例:

          [root@linux redis]# ruby redis-trib.rb reshard --from all --to 34aff9de9f005b23dc1ae090d1791edb6277b255 --slots 200 --yes 192.168.127.129:7000
          >>> Performing Cluster Check (using node 192.168.127.129:7000)
          M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
             slots:0-5460 (5461 slots) master
             1 additional replica(s)
          S: 30a872bdf2ec16fabbd8fcb7e08514dffec09364 192.168.127.129:7005
             slots: (0 slots) slave
             replicates 7e41f26c96c796c6ad546df836b93d2aadf9e13c
          M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
             slots:10923-16383 (5461 slots) master
             1 additional replica(s)
          S: 69ada8a4fe3784597480bd8bddbeb57ab08a8f34 192.168.127.129:7004
             slots: (0 slots) slave
             replicates d16665971f9a1f5715fd7365314436c99ba6e7ef
          M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
             slots:5461-10922 (5462 slots) master
             1 additional replica(s)
          M: 34aff9de9f005b23dc1ae090d1791edb6277b255 192.168.127.129:7006
             slots: (0 slots) master
             0 additional replica(s)
          S: ee0e0688c0258c34f9673a44e5bc97374abaeb5d 192.168.127.129:7003
             slots: (0 slots) slave
             replicates 454e7e2ca5e70103ae19926e139dc212ad084637
          [OK] All nodes agree about slots configuration.
          >>> Check for open slots...
          >>> Check slots coverage...
          [OK] All 16384 slots covered.

          Ready to move 200 slots.
            Source nodes:
              M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
             slots:0-5460 (5461 slots) master
             1 additional replica(s)
              M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
           slots:10923-16383 (5461 slots) master
             1 additional replica(s)
              M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
             slots:5461-10922 (5462 slots) master
             1 additional replica(s)
            Destination node:
              M: 34aff9de9f005b23dc1ae090d1791edb6277b255 192.168.127.129:7006
             slots: (0 slots) master
             0 additional replica(s)
            Resharding plan:
          Moving slot 5461 from d16665971f9a1f5715fd7365314436c99ba6e7ef
          Moving slot 5462 from d16665971f9a1f5715fd7365314436c99ba6e7ef
          Moving slot 5463 from d16665971f9a1f5715fd7365314436c99ba6e7ef
          Moving slot 5464 from d16665971f9a1f5715fd7365314436c99ba6e7ef
          Moving slot 5465 from d16665971f9a1f5715fd7365314436c99ba6e7ef
          //省略。。。。
          Moving slot 10943 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10977 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10978 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10979 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10980 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10981 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10982 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10983 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10984 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10985 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10986 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10987 from 192.168.127.129:7002 to 192.168.127.129:7006: 
          Moving slot 10988 from 192.168.127.129:7002 to 192.168.127.129:7006: 

 
              遷移的流程如下:

                  1、通過load_cluster_info_from_node方法裝載集群信息。

                  2、執行check_cluster方法檢查集群是否健康。只有健康的集群才能進行遷移。

                  3、獲取需要遷移的slot數量,用戶沒傳遞--slots參數,則提示用戶手動輸入。

                  4、獲取遷移的目的節點,用戶沒傳遞--to參數,則提示用戶手動輸入。此處會檢查目的節點必須為master節點。

                  5、獲取遷移的源節點,用戶沒傳遞--from參數,則提示用戶手動輸入。此處會檢查源節點必須為master節點。--from all的話,源節點就是除了目的節點外的全部master節點。這里為了保證集群slot分配的平均,建議傳遞--from all。

                  6、執行compute_reshard_table方法,計算需要遷移的slot數量如何分配到源節點列表,采用的算法是按照節點負責slot數量由多到少排序,計算每個節點需要遷移的slot的方法為:遷移slot數量 * (該源節點負責的slot數量 / 源節點列表負責的slot總數)。這樣算出的數量可能不為整數,這里代碼用了下面的方式處理:

                  n = (numslots/source_tot_slots*s.slots.length)
                  if i == 0
                      n = n.ceil
                  else
                      n = n.floor
        
                  這樣的處理方式會帶來最終分配的slot與請求遷移的slot數量不一致,這個BUG已經在github上提給作者,    https://github.com/antirez/redis/issues/2990。

                  7、打印出reshard計划,如果用戶沒傳--yes,就提示用戶確認計划。

                  8、根據reshard計划,一個個slot的遷移到新節點上,遷移使用move_slot方法,該方法被很多命令使用,具體可以參見下面的遷移流程。move_slot方法傳遞dots為true和pipeline數量。

                  9、至此,就完成了全部的遷移任務。


                  move_slot方法可以在線將一個slot的全部數據從源節點遷移到目的節點,fix、reshard、rebalance都需要調用該方法遷移slot。

                  move_slot接受下面幾個參數,

                      1、pipeline:設置一次從slot上獲取多少個key。

                      2、quiet:遷移會打印相關信息,設置quiet參數,可以不用打印這些信息。

                      3、cold:設置cold,會忽略執行importing和migrating。

                      4、dots:設置dots,則會在遷移過程打印遷移key數量的進度。

                      5、update:設置update,則會更新內存信息,方便以后的操作。


                  move_slot流程如下:

                      1、如果沒有設置cold,則對源節點執行cluster importing命令,對目的節點執行migrating命令。fix的時候有可能importing和migrating已經執行過來,所以此種場景會設置cold。

                      2、通過cluster getkeysinslot命令,一次性獲取遠節點遷移slot的pipeline個key的數量.

                      3、對這些key執行migrate命令,將數據從源節點遷移到目的節點。

                      4、如果migrate出現異常,在fix模式下,BUSYKEY的異常,會使用migrate的replace模式再執行一次,BUSYKEY表示目的節點已經有該key了,replace模式可以強制替換目的節點的key。不是fix模式就直接返回錯誤了。

                      5、循環執行cluster getkeysinslot命令,直到返回的key數量為0,就退出循環。

                      6、如果沒有設置cold,對每個節點執行cluster setslot命令,把slot賦給目的節點。

                      7、如果設置update,則修改源節點和目的節點的slot信息。

                      8、至此完成了遷移slot的流程。


        7、Rebalance平衡集群節點slot數量

               命令格式:ruby redis-trib.rb  rebalance --weight <arg>  host:port【此地址可以是集群中任何一個節點的地址,相當於獲取集群信息的入口】
                                                     --auto-weights
                                                       --threshold <arg>
                                                                                     --use-empty-masters
                                                                                     --timeout <arg>
                                                                                     --simulate
                                                                                     --pipeline <arg>

              rebalance命令可以根據用戶傳入的參數平衡集群節點的slot數量,rebalance功能非常強大,可以傳入的參數很多。

 

        以下是rebalance的參數列表和命令示例。
              # ruby redis-trib.rb rebalance --threshold 1 --weight b31e3a2e=5 --weight 60b8e3a1=5 --use-empty-masters  --simulate 10.180.157.199:6379


              下面也先一一解釋下每個參數的用法:

                   host:port:這個是必傳參數,用來從一個節點獲取整個集群信息,相當於獲取集群信息的入口。

                  --weight <arg>:節點的權重,格式為node_id=weight,如果需要為多個節點分配權重的話,需要添加多個--weight <arg>參數,即--weight b31e3a2e=5 --weight 60b8e3a1=5,node_id可為節點名稱的前綴,只要保證前綴位數能唯一區分該節點即可。沒有傳遞    –weight的節點的權重默認為1。

                  --auto-weights:這個參數在rebalance流程中並未用到。

                  --threshold <arg>:只有節點需要遷移的slot閾值超過threshold,才會執行rebalance操作。具體計算方法可以參考下面的rebalance命令流程的第四步。

                  --use-empty-masters:rebalance是否考慮沒有節點的master,默認沒有分配slot節點的master是不參與rebalance的,設置--use-empty-masters可以讓沒有分配slot的節點參與rebalance。

                  --timeout <arg>:設置migrate命令的超時時間。

                  --simulate:設置該參數,可以模擬rebalance操作,提示用戶會遷移哪些slots,而不會真正執行遷移操作。

                  --pipeline <arg>:與reshar的pipeline參數一樣,定義cluster getkeysinslot命令一次取出的key數量,不傳的話使用默認值為10。


               rebalance命令流程如下:

                    1、load_cluster_info_from_node方法先加載集群信息。

                    2、計算每個master的權重,根據參數--weight <arg>,為每個設置的節點分配權重,沒有設置的節點,則權重默認為1。

                    3、根據每個master的權重,以及總的權重,計算自己期望被分配多少個slot。計算的方式為:總slot數量 * (自己的權重 / 總權重)。

                    4、計算每個master期望分配的slot是否超過設置的閾值,即--threshold <arg>設置的閾值或者默認的閾值。計算的方式為:先計算期望移動節點的閾值,算法為:(100-(100.0*expected/n.slots.length)).abs,如果計算出的閾值沒有超出設置閾值,則不需要為該節點移動slot。只要有一個master的移動節點超過閾值,就會觸發rebalance操作。

                    5、如果觸發了rebalance操作。那么就開始執行rebalance操作,先將每個節點當前分配的slots數量減去期望分配的slot數量獲得balance值。將每個節點的balance從小到大進行排序獲得sn數組。

                    6、用dst_idx和src_idx游標分別從sn數組的頭部和尾部開始遍歷。目的是為了把尾部節點的slot分配給頭部節點。

              sn數組保存的balance列表排序后,負數在前面,正數在后面。負數表示需要有slot遷入,所以使用dst_idx游標,正數表示需要有slot遷出,所以使用src_idx游標。理論上sn數組各節點的balance值加起來應該為0,不過由於在計算期望分配的slot的時候只是使用直接取整的方式,所以可能出現balance值之和不為0的情況,balance值之和不為0即為節點不平衡的slot數量,由於slot總數有16384個,不平衡數量相對於總數,基數很小,所以對rebalance流程影響不大。

                    7、獲取sn[dst_idx]和sn[src_idx]的balance值較小的那個值,該值即為需要從sn[src_idx]節點遷移到sn[dst_idx]節點的slot數量。

                    8、接着通過compute_reshard_table方法計算源節點的slot如何分配到源節點列表。這個方法在reshard流程中也有調用,具體步驟可以參考reshard流程的第六步。

                    9、如果是simulate模式,則只是打印出遷移列表。

                    10、如果沒有設置simulate,則執行move_slot操作,遷移slot,傳入的參數為:quiet=>true,:dots=>false,:update=>true。

                    11、遷移完成后更新sn[dst_idx]和sn[src_idx]的balance值。如果balance值為0后,游標向前進1。

                    12、直到dst_idx到達src_idx游標,完成整個rebalance操作。


        8、add-node將新節點加入集群

              命令格式:ruby redis-trib.rb add-node --slave  new_host:new_port existing_host:existing_port【此地址可以是集群中任何一個節點的地址,相當於獲取集群信息的入口】
                                                 --master-id <arg>

              add-node命令可以將新節點加入集群,節點可以為master,也可以為某個master節點的slave。

              add-node有兩個可選參數:

                    --slave:設置該參數,則新節點以slave的角色加入集群

                    --master-id:這個參數需要設置了--slave才能生效,--master-id用來指定新節點的master節點。如果不設置該參數,則會隨機為節點選擇master節點。

            這兩個參數(--slave,--master-id)並沒有先后順序,但是這兩個參數必須在 add-node 之后,new_host:new_port existing_host:existing_port參數之前。

              可以看下add-node命令的執行示例(我們將192.168.127.129:7003作為192.168.127.129:7000的從節點增加進集群):

          [root@linux redis]# ruby redis-trib.rb add-node --slave --master-id 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7003 192.168.127.129:7000
          >>> Adding node 192.168.127.129:7003 to cluster 192.168.127.129:7000
          >>> Performing Cluster Check (using node 192.168.127.129:7000)
          M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
             slots:0-5460 (5461 slots) master
             0 additional replica(s)
          M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
             slots:5461-10922 (5462 slots) master
             0 additional replica(s)
          M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
             slots:10923-16383 (5461 slots) master
             0 additional replica(s)
          [OK] All nodes agree about slots configuration.
          >>> Check for open slots...
          >>> Check slots coverage...
          [OK] All 16384 slots covered.
          >>> Send CLUSTER MEET to node 192.168.127.129:7003 to make it join the cluster.
          Waiting for the cluster to join.
          >>> Configure node as replica of 192.168.127.129:7000.
          [OK] New node added correctly.

              可以看下add-node命令的執行示例(我們將192.168.127.129:7004作為192.168.127.129:7001的從節點增加進集群):

          [root@linux redis]# ruby redis-trib.rb add-node --slave --master-id d16665971f9a1f5715fd7365314436c99ba6e7ef  192.168.127.129:7004 192.168.127.129:7001
          >>> Adding node 192.168.127.129:7004 to cluster 192.168.127.129:7001
          >>> Performing Cluster Check (using node 192.168.127.129:7001)
          M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
             slots:5461-10922 (5462 slots) master
             0 additional replica(s)
          S: ee0e0688c0258c34f9673a44e5bc97374abaeb5d 192.168.127.129:7003
             slots: (0 slots) slave
             replicates 454e7e2ca5e70103ae19926e139dc212ad084637
          M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
             slots:0-5460 (5461 slots) master
             1 additional replica(s)
          M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
             slots:10923-16383 (5461 slots) master
             0 additional replica(s)
          [OK] All nodes agree about slots configuration.
          >>> Check for open slots...
          >>> Check slots coverage...
          [OK] All 16384 slots covered.
          >>> Send CLUSTER MEET to node 192.168.127.129:7004 to make it join the cluster.
          Waiting for the cluster to join.
          >>> Configure node as replica of 192.168.127.129:7001.
          [OK] New node added correctly.
          [root@linux redis]# 

              可以看下add-node命令的執行示例(我們將192.168.127.129:7005作為192.168.127.129:7000的從節點增加進集群,此時7000已有從節點,但是7005並沒有作為7000的從節點,而是作為7002的從節點,因為當時7002沒從節點):

          [root@linux redis]# ruby redis-trib.rb add-node --master-id 454e7e2ca5e70103ae19926e139dc212ad084637  --slave  192.168.127.129:7005 192.168.127.129:7000
          >>> Adding node 192.168.127.129:7005 to cluster 192.168.127.129:7000
          >>> Performing Cluster Check (using node 192.168.127.129:7000)
          M: 454e7e2ca5e70103ae19926e139dc212ad084637 192.168.127.129:7000
             slots:0-5460 (5461 slots) master
             1 additional replica(s)
          M: 7e41f26c96c796c6ad546df836b93d2aadf9e13c 192.168.127.129:7002
             slots:10923-16383 (5461 slots) master
           0 additional replica(s)
          S: 69ada8a4fe3784597480bd8bddbeb57ab08a8f34 192.168.127.129:7004
             slots: (0 slots) slave
             replicates d16665971f9a1f5715fd7365314436c99ba6e7ef
          M: d16665971f9a1f5715fd7365314436c99ba6e7ef 192.168.127.129:7001
             slots:5461-10922 (5462 slots) master
             1 additional replica(s)
          S: ee0e0688c0258c34f9673a44e5bc97374abaeb5d 192.168.127.129:7003
             slots: (0 slots) slave
             replicates 454e7e2ca5e70103ae19926e139dc212ad084637
          [OK] All nodes agree about slots configuration.
          >>> Check for open slots...
          >>> Check slots coverage...
          [OK] All 16384 slots covered.
          >>> Send CLUSTER MEET to node 192.168.127.129:7005 to make it join the cluster.
          Waiting for the cluster to join.
          >>> Configure node as replica of 192.168.127.129:7000.
          [OK] New node added correctly.


              add-node流程如下:

                    1、通過load_cluster_info_from_node方法轉載集群信息,check_cluster方法檢查集群是否健康。

                    2、如果設置了--slave,則需要為該節點尋找master節點。設置了--master-id,則以該節點作為新節點的master,如果沒有設置--master-id,則調用get_master_with_least_replicas方法,尋找slave數量最少的master節點。如果slave數量一致,則選取load_cluster_info_from_node順序發現的第一個節點。load_cluster_info_from_node順序的第一個節點是add-node設置的existing_host:existing_port節點,后面的順序根據在該節點執行cluster nodes返回的結果返回的節點順序。

                    3、連接新的節點並與集群第一個節點握手。

                    4、如果沒設置–slave就直接返回ok,設置了–slave,則需要等待確認新節點加入集群,然后執行cluster replicate命令復制master節點。

                    5、至此,完成了全部的增加節點的流程。


        9、del-node從集群中刪除節點

              命令格式:ruby redis-trib.rb del-node host:port node-id【node id是要刪除的節點ID標識】

              del-node可以把某個節點從集群中刪除。del-node只能刪除沒有分配slot的節點。刪除命令傳遞兩個參數:

              host:port:從該節點獲取集群信息。

              node_id:需要刪除的節點id。

              del-node執行結果示例如下:

          [root@linux redis]# ruby redis-trib.rb del-node 192.168.127.129:7006 34aff9de9f005b23dc1ae090d1791edb6277b255
          >>> Removing node 34aff9de9f005b23dc1ae090d1791edb6277b255 from cluster 192.168.127.129:7006
          >>> Sending CLUSTER FORGET messages to the cluster...
          >>> SHUTDOWN the node.


              del-node流程如下:

                  1、通過load_cluster_info_from_node方法轉載集群信息。

                  2、根據傳入的node id獲取節點,如果節點沒找到,則直接提示錯誤並退出。

                  3、如果節點分配的slot不為空,則直接提示錯誤並退出。

                  4、遍歷集群內的其他節點,執行cluster forget命令,從每個節點中去除該節點。如果刪除的節點是master,而且它有slave的話,這些slave會去復制其他master,調用的方法是get_master_with_least_replicas,與add-node沒設置--master-id尋找master的方法一樣。

                  5、然后關閉該節點


        10、set-timeout設置集群節點間心跳連接的超時時間

              命令格式:ruby redis-trib.rb set-timeout host:port  milliseconds

              set-timeout用來設置集群節點間心跳連接的超時時間,單位是毫秒,不得小於100毫秒,因為100毫秒對於心跳時間來說太短了。該命令修改是節點配置參數cluster-node-timeout,默認是15000毫秒。通過該命令,可以給每個節點設置超時時間,設置的方式使用config set命令動態設置,然后執行config rewrite命令將配置持久化保存到硬盤。以下是示例:

        [root@linux redis]# ruby redis-trib.rb set-timeout 192.168.127.130:7000 15000
        >>> Reconfiguring node timeout in every cluster node...
        *** New timeout set for 192.168.127.130:7000
        *** New timeout set for 192.168.127.130:7002
        *** New timeout set for 192.168.127.130:7003
        *** New timeout set for 192.168.127.130:7005
        *** New timeout set for 192.168.127.130:7004
        *** New timeout set for 192.168.127.130:7001
        >>> New node timeout set. 6 OK, 0 ERR.


        11、call在集群全部節點上執行命令

              命令格式:ruby redis-trib.rb call host:port [command redis的命令]

              call命令可以用來在集群的全部節點執行相同的命令。call命令也是需要通過集群的一個節點地址,連上整個集群,然后在集群的每個節點執行該命令。
    

            [root@linux redis]# ruby redis-trib.rb call 192.168.127.130:7000 get key
         >>> Calling GET key
         192.168.127.130:7000: MOVED 12539 192.168.127.130:7002
         192.168.127.130:7002:
         192.168.127.130:7003: MOVED 12539 192.168.127.130:7002
         192.168.127.130:7005: MOVED 12539 192.168.127.130:7002
         192.168.127.130:7004: MOVED 12539 192.168.127.130:7002
         192.168.127.130:7001: MOVED 12539 192.168.127.130:7002


        12、import將外部redis數據導入集群

              命令格式:ruby redis-trib.rb import --from host:port host:port

              執行示例如下:

            [root@linux redis]# ruby redis-trib.rb import --from 192.168.127.130:7006 192.168.127.129:7000

              上面的命令是把 192.168.127.130:7006(redis 4.8)上的數據導入到 192.168.127.129:7000 這個節點所在的集群


              import命令可以把外部的redis節點數據導入集群。導入的流程如下:

                1、通過load_cluster_info_from_node方法轉載集群信息,check_cluster方法檢查集群是否健康。

                2、連接外部redis節點,如果外部節點開啟了cluster_enabled,則提示錯誤。

                3、通過scan命令遍歷外部節點,一次獲取1000條數據。

                4、遍歷這些key,計算出key對應的slot。

                5、執行migrate命令,源節點是外部節點,目的節點是集群slot對應的節點,如果設置了--copy參數,則傳遞copy參數,如果設置了--replace,則傳遞replace參數。

                6、不停執行scan命令,直到遍歷完全部的key。

                7、至此完成整個遷移流程

                這中間如果出現異常,程序就會停止。沒使用--copy模式,則可以重新執行import命令,使用--copy的話,最好清空新的集群再導入一次。

                import命令更適合離線的把外部redis數據導入,在線導入的話最好使用更專業的導入工具,以slave的方式連接redis節點去同步節點數據應該是更好的方式。


三、總結

        好了,今天就寫到這里,有關redis-trib.rb腳步文件的內容還很多,以后再補充進來吧。這個腳本文件對我們很重要,集群的操作很多功能都可以通過這個腳本文件來完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM