redis cluster管理工具redis-trib.rb详解

1、先从redis-trib.rb的help信息,看下redis-trib.rb提供了哪些功能。

 

$ruby redis-trib.rb help
Usage: redis-trib <command> <options> <arguments ...>
  1.create:建立集群
  create          host1:port1 ... hostN:portN
                  --replicas <arg>
  2.check:检查集群              
  check           host:port
  3.info:查看集群信息
  info            host:port
  4.fix:修复集群
  fix             host:port
                  --timeout <arg>
  5.reshard:在线迁移slot
  reshard         host:port
                  --from <arg>
                  --to <arg>
                  --slots <arg>
                  --yes
                  --timeout <arg>
                  --pipeline <arg>
  6.rebalance:平衡集群节点slot数量                  
  rebalance       host:port
                  --weight <arg>
                  --auto-weights
                  --threshold <arg>
                  --use-empty-masters
                  --timeout <arg>
                  --simulate
                  --pipeline <arg>
  7.add-node:将新节点加入集群                  
  add-node        new_host:new_port existing_host:existing_port
                  --slave
                  --master-id <arg>
  8.del-node:从集群中删除节点                  
  del-node        host:port node_id
  9.set-timeout:设置集群节点间心跳链接的超时时间
  set-timeout     host:port milliseconds
  10.call:在集群所有节点上执行命令
  call            host:port command arg arg .. arg
  11.import:将外部redis数据导入集群
  import          host:port
                  --from <arg>
                  --copy
                  --replace
  help            (show this help)

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

 

2、下面从redis-trib.rb使用和源码的角度详细介绍redis-trib.rb的每一个功能。

 

redis-trib.rb主要有两个类:ClusterNode和RedisTrib。ClusterNode保存了每一个节点的信息,RedisTrib则是redis-trib.rb各个功能的实现。

ClusterNode对象

先分析ClusterNode源码。ClusterNode有下面几个成员变量(ruby的类成员变量是以@开头的):

@r:执行redis命令的客户端对象。
@info:保存了该节点的详细信息,包括cluster nodes命令中本身这行的信息和cluster info的信息。
@dirty:节点信息是否须要更新,若是为true,咱们须要把内存的节点更新信息到节点上。
@friends:保存了集群其余节点的info信息。其信息为经过cluster nodes命令得到的其余节点信息。
ClusterNode有下面一些成员方法:

initialize:ClusterNode的构造方法,须要传入节点的地址信息。
friends:返回@friends对象。
slots:返回该节点负责的slots信息。
has_flag?:判断节点info信息的的flags中是否有给定的flag。
to_s:相似java的toString方法,返回节点的地址信息。
connect:链接redis节点。
assert_cluster:判断节点开启了集群配置。
assert_empty:肯定节点目前没有跟任何其余节点握手,同时本身的db数据为空。
load_info:经过cluster info和cluster nodes导入节点信息。
add_slots:给节点增长slot,该操做只是在内存中修改,并把dirty设置成true,等待flush_node_config将内存中的数据同步在节点执行。
set_as_replica:slave设置复制的master地址。dirty设置成true。
flush_node_config:将内存的数据修改同步在集群节点中执行。
info_string:简单的info信息。
get_config_signature:用来验证集群节点见的cluster nodes信息是否一致。该方法返回节点的签名信息。
info:返回@info对象,包含详细的info信息。
is_dirty?:判断@dirty。
r:返回执行redis命令的客户端对象。
有了ClusterNode对象,在处理集群操做的时候,就得到了集群的信息,能够进行集群相关操做。在此先简单介绍下redis-trib.rb脚本的使用,以create为例:

create host1:port1 ... hostN:portN
       --replicas <arg>
host1:port1 ... hostN:portN表示子参数,这个必须在可选参数以后,--replicas <arg>是可选参数,带的表示后面必须填写一个参数,像--slave这样,后面就不带参数,掌握了这个基本规则,就能从help命令中得到redis-trib.rb的使用方法。

其余命令大都须要传递host:port,这是redis-trib.rb为了链接集群,须要选择集群中的一个节点,而后经过该节点得到整个集群的信息。

 

3、详细介绍redis-trib.rb的每一个功能。

3.1 create建立集群

 

Usage: redis-trib <command> <options> <arguments ...>
  create          host1:port1 ... hostN:portN
                  --replicas <arg>
create命令可选replicas参数,replicas表示须要有几个slave。最简单命令使用以下:

$ruby redis-trib.rb create 10.180.157.199:6379 10.180.157.200:6379 10.180.157.201:6379
有一个slave的建立命令以下:

$ruby redis-trib.rb create --replicas 1 10.180.157.199:6379 10.180.157.200:6379 10.180.157.201:6379 10.180.157.202:6379  10.180.157.205:6379  10.180.157.208:6379 
建立流程以下:

一、首先为每一个节点建立ClusterNode对象,包括链接每一个节点。检查每一个节点是否为独立且db为空的节点。执行load_info方法导入节点信息。
二、检查传入的master节点数量是否大于等于3个。只有大于3个节点才能组成集群。
三、计算每一个master须要分配的slot数量,以及给master分配slave。分配的算法大体以下:
先把节点按照host分类,这样保证master节点能分配到更多的主机中。
不停遍历遍历host列表,从每一个host列表中弹出一个节点,放入interleaved数组。直到全部的节点都弹出为止。
master节点列表就是interleaved前面的master数量的节点列表。保存在masters数组。
计算每一个master节点负责的slot数量,保存在slots_per_node对象,用slot总数除以master数量取整便可。
遍历masters数组,每一个master分配slots_per_node个slot,最后一个master,分配到16384个slot为止。
接下来为master分配slave,分配算法会尽可能保证master和slave节点不在同一台主机上。对于分配完指定slave数量的节点,还有多余的节点,也会为这些节点寻找master。分配算法会遍历两次masters数组。
第一次遍历masters数组,在余下的节点列表找到replicas数量个slave。每一个slave为第一个和master节点host不同的节点,若是没有不同的节点,则直接取出余下列表的第一个节点。
第二次遍历是在对于节点数除以replicas不为整数,则会多余一部分节点。遍历的方式跟第一次同样,只是第一次会一次性给master分配replicas数量个slave,而第二次遍历只分配一个,直到余下的节点被所有分配出去。
四、打印出分配信息,并提示用户输入“yes”确认是否按照打印出来的分配方式建立集群。
五、输入“yes”后,会执行flush_nodes_config操做,该操做执行前面的分配结果,给master分配slot,让slave复制master,对于尚未握手(cluster meet)的节点,slave复制操做没法完成,不过不要紧,flush_nodes_config操做出现异常会很快返回,后续握手后会再次执行flush_nodes_config。
六、给每一个节点分配epoch,遍历节点,每一个节点分配的epoch比以前节点大1。
七、节点间开始相互握手,握手的方式为节点列表的其余节点跟第一个节点握手。
八、而后每隔1秒检查一次各个节点是否已经消息同步完成,使用ClusterNode的get_config_signature方法,检查的算法为获取每一个节点cluster nodes信息,排序每一个节点,组装成node_id1:slots|node_id2:slot2|...的字符串。若是每一个节点得到字符串都相同,即认为握手成功。
九、此后会再执行一次flush_nodes_config,此次主要是为了完成slave复制操做。
十、最后再执行check_cluster,全面检查一次集群状态。包括和前面握手时检查同样的方式再检查一遍。确认没有迁移的节点。确认全部的slot都被分配出去了。
十一、至此完成了整个建立流程,返回[OK] All 16384 slots covered.。

 

3.2 check检查集群

 

Usage: redis-trib <command> <options> <arguments ...>  
  check           host:port

检查集群状态的命令,没有其余参数,只须要选择一个集群中的一个节点便可。执行命令以及结果以下:


$ruby redis-trib.rb check 10.180.157.199:6379

>>> Performing Cluster Check (using node 10.180.157.199:6379)

M: b2506515b38e6bbd3034d540599f4cd2a5279ad1 10.180.157.199:6379

   slots:0-5460 (5461 slots) master

   1 additional replica(s)

S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 10.180.157.205:6379

   slots: (0 slots) slave

   replicates e36c46dbe90960f30861af00786d4c2064e63df2

M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379

   slots:10923-16383 (5461 slots) master

   1 additional replica(s)

S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 10.180.157.208:6379

   slots: (0 slots) slave

   replicates 15126fb33796c2c26ea89e553418946f7443d5a5

S: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379

   slots: (0 slots) slave

   replicates b2506515b38e6bbd3034d540599f4cd2a5279ad1

M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379

   slots:5461-10922 (5462 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.    

检查前会先执行load_cluster_info_from_node方法,把全部节点数据load进来。load的方式为经过本身的cluster nodes发现其余节点,而后链接每一个节点,并加入nodes数组。接着生成节点间的复制关系。


load完数据后,开始检查数据,检查的方式也是调用建立时候使用的check_cluster。

 

 3.3 info查看集群信息

 

Usage: redis-trib <command> <options> <arguments ...>  
  info            host:port
info命令用来查看集群的信息。info命令也是先执行load_cluster_info_from_node获取完整的集群信息。而后显示ClusterNode的info_string结果,示例以下:


$ruby redis-trib.rb info 10.180.157.199:6379

10.180.157.199:6379 (b2506515...) -> 0 keys | 5461 slots | 1 slaves.

10.180.157.201:6379 (15126fb3...) -> 0 keys | 5461 slots | 1 slaves.

10.180.157.200:6379 (e36c46db...) -> 0 keys | 5462 slots | 1 slaves.

[OK] 0 keys in 3 masters.

0.00 keys per slot on average.

 

 3.4 fix修复集群

 

Usage: redis-trib <command> <options> <arguments ...>
  fix             host:port
                  --timeout <arg>

fix命令的流程跟check的流程很像,显示加载集群信息,而后在check_cluster方法内传入fix为true的变量,会在集群检查出现异常的时候执行修复流程。
目前fix命令能修复两种异常,一种是集群有处于迁移中的slot的节点,一种是slot未彻底分配的异常。

fix_open_slot方法是修复集群有处于迁移中的slot的节点异常。

一、先检查该slot是谁负责的,迁移的源节点若是没完成迁移,owner仍是该节点。没有owner的slot没法完成修复功能。

二、遍历每一个节点,获取哪些节点标记该slot为migrating状态,哪些节点标记该slot为importing状态。对于owner不是该节点,可是经过cluster
 countkeysinslot获取到该节点有数据的状况,也认为该节点为importing状态。

三、若是migrating和importing状态的节点均只有1个,这多是迁移过程当中redis-trib.rb被中断所致,直接执行move_slot继续完成迁移任务便可。传递dots和fix为true。

四、若是migrating为空,importing状态的节点大于0,那么这种状况执行回滚流程,将importing状态的节点数据经过move_slot方法导给slot的owner节点,传递dots、fix和cold为true。接着对importing的节点执行cluster
 stable命令恢复稳定。

五、若是importing状态的节点为空,有一个migrating状态的节点,并且该节点在当前slot没有数据,那么能够直接把这个slot设为stable。

六、若是migrating和importing状态不是上述状况,目前redis-trib.rb工具没法修复,上述的三种状况也已经覆盖了经过redis-trib.rb工具迁移出现异常的各个方面,人为的异常情形太多,很难考虑彻底。

fix_slots_coverage方法能修复slot未彻底分配的异常。未分配的slot有三种状态。

一、全部节点的该slot都没有数据。该状态redis-trib.rb工具直接采用随机分配的方式,并无考虑节点的均衡。本人尝试对没有分配slot的集群经过fix修复集群,结果slot仍是能比较平均的分配,可是没有了连续性,打印的slot信息很是离散。

二、有一个节点的该slot有数据。该状态下,直接把slot分配给该slot有数据的节点。

三、有多个节点的该slot有数据。此种状况目前还处于TODO状态,不过redis做者列出了修复的步骤,对这些节点,除第一个节点,执行cluster
 migrating命令,而后把这些节点的数据迁移到第一个节点上。清除migrating状态,而后把slot分配给第一个节点。

 

3.5 reshard在线迁移slot

 

Usage: redis-trib <command> <options> <arguments ...>
  reshard         host:port
                  --from <arg>
                  --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。

迁移的流程以下:

一、经过load_cluster_info_from_node方法装载集群信息。

二、执行check_cluster方法检查集群是否健康。只有健康的集群才能进行迁移。

三、获取须要迁移的slot数量,用户没传递--slots参数,则提示用户手动输入。

四、获取迁移的目的节点,用户没传递--to参数,则提示用户手动输入。此处会检查目的节点必须为master节点。

五、获取迁移的源节点,用户没传递--from参数,则提示用户手动输入。此处会检查源节点必须为master节点。--from all的话,源节点就是除了目的节点外的所有master节点。这里为了保证集群slot分配的平均,建议传递--from all。

六、执行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。

七、打印出reshard计划,若是用户没传--yes,就提示用户确认计划。

八、根据reshard计划,一个个slot的迁移到新节点上,迁移使用move_slot方法,该方法被不少命令使用,具体能够参见下面的迁移流程。move_slot方法传递dots为true和pipeline数量。

九、至此,就完成了所有的迁移任务。

下面看下一次reshard的执行结果:

$ruby redis-trib.rb reshard --from all --to 80b661ecca260c89e3d8ea9b98f77edaeef43dcd --slots 11 10.180.157.199:6379

>>> Performing Cluster Check (using node 10.180.157.199:6379)

S: b2506515b38e6bbd3034d540599f4cd2a5279ad1 10.180.157.199:6379

   slots: (0 slots) slave

   replicates 460b3a11e296aafb2615043291b7dd98274bb351

S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 10.180.157.205:6379

   slots: (0 slots) slave

   replicates e36c46dbe90960f30861af00786d4c2064e63df2

M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379

   slots:10923-16383 (5461 slots) master

   1 additional replica(s)

S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 10.180.157.208:6379

   slots: (0 slots) slave

   replicates 15126fb33796c2c26ea89e553418946f7443d5a5

M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379

   slots:0-5460 (5461 slots) master

   1 additional replica(s)

M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380

   slots: (0 slots) master

   0 additional replica(s)

M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379

   slots:5461-10922 (5462 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.


Ready to move 11 slots.

  Source nodes:

    M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379

   slots:10923-16383 (5461 slots) master

   1 additional replica(s)

    M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379

   slots:0-5460 (5461 slots) master

   1 additional replica(s)

    M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379

   slots:5461-10922 (5462 slots) master

   1 additional replica(s)

  Destination node:

    M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380

   slots: (0 slots) master

   0 additional replica(s)

  Resharding plan:

    Moving slot 5461 from e36c46dbe90960f30861af00786d4c2064e63df2

    Moving slot 5462 from e36c46dbe90960f30861af00786d4c2064e63df2

    Moving slot 5463 from e36c46dbe90960f30861af00786d4c2064e63df2

    Moving slot 5464 from e36c46dbe90960f30861af00786d4c2064e63df2

    Moving slot 0 from 460b3a11e296aafb2615043291b7dd98274bb351

    Moving slot 1 from 460b3a11e296aafb2615043291b7dd98274bb351

    Moving slot 2 from 460b3a11e296aafb2615043291b7dd98274bb351

    Moving slot 10923 from 15126fb33796c2c26ea89e553418946f7443d5a5

    Moving slot 10924 from 15126fb33796c2c26ea89e553418946f7443d5a5

    Moving slot 10925 from 15126fb33796c2c26ea89e553418946f7443d5a5

Do you want to proceed with the proposed reshard plan (yes/no)? yes

Moving slot 5461 from 10.180.157.200:6379 to 10.180.157.200:6380:

Moving slot 5462 from 10.180.157.200:6379 to 10.180.157.200:6380:

Moving slot 5463 from 10.180.157.200:6379 to 10.180.157.200:6380:

Moving slot 5464 from 10.180.157.200:6379 to 10.180.157.200:6380:

Moving slot 0 from 10.180.157.202:6379 to 10.180.157.200:6380:

Moving slot 1 from 10.180.157.202:6379 to 10.180.157.200:6380:

Moving slot 2 from 10.180.157.202:6379 to 10.180.157.200:6380:

Moving slot 10923 from 10.180.157.201:6379 to 10.180.157.200:6380:

Moving slot 10924 from 10.180.157.201:6379 to 10.180.157.200:6380:

Moving slot 10925 from 10.180.157.201:6379 to 10.180.157.200:6380:

move_slot方法能够在线将一个slot的所有数据从源节点迁移到目的节点,fix、reshard、rebalance都须要调用该方法迁移slot。


move_slot接受下面几个参数,

一、pipeline:设置一次从slot上获取多少个key。

二、quiet:迁移会打印相关信息,设置quiet参数,能够不用打印这些信息。

三、cold:设置cold,会忽略执行importing和migrating。

四、dots:设置dots,则会在迁移过程打印迁移key数量的进度。

五、update:设置update,则会更新内存信息,方便之后的操做。

move_slot流程以下:


一、若是没有设置cold,则对源节点执行cluster importing命令,对目的节点执行migrating命令。fix的时候有可能importing和migrating已经执行过来,因此此种场景会设置cold。

二、经过cluster getkeysinslot命令,一次性获取远节点迁移slot的pipeline个key的数量.

三、对这些key执行migrate命令,将数据从源节点迁移到目的节点。

四、若是migrate出现异常,在fix模式下,BUSYKEY的异常,会使用migrate的replace模式再执行一次,BUSYKEY表示目的节点已经有该key了,replace模式能够强制替换目的节点的key。不是fix模式就直接返回错误了。

五、循环执行cluster getkeysinslot命令,直到返回的key数量为0,就退出循环。

六、若是没有设置cold,对每一个节点执行cluster setslot命令,把slot赋给目的节点。

七、若是设置update,则修改源节点和目的节点的slot信息。

八、至此完成了迁移slot的流程。

 

3.6 rebalance平衡集群节点slot数量

 

Usage: redis-trib <command> <options> <arguments ...>
  rebalance       host:port
                  --weight <arg>
                  --auto-weights
                  --threshold <arg>
                  --use-empty-masters
                  --timeout <arg>
                  --simulate
                  --pipeline <arg>

  rebalance命令能够根据用户传入的参数平衡集群节点的slot数量,rebalance功能很是强大,能够传入的参数不少,如下是rebalance的参数列表和命令示例。java

$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命令流程以下:

一、load_cluster_info_from_node方法先加载集群信息。

二、计算每一个master的权重,根据参数--weight <arg>,为每一个设置的节点分配权重,没有设置的节点,则权重默认为1。

三、根据每一个master的权重,以及总的权重,计算本身指望被分配多少个slot。计算的方式为:总slot数量 * (本身的权重 / 总权重)。

四、计算每一个master指望分配的slot是否超过设置的阈值,即--threshold 
<arg>设置的阈值或者默认的阈值。计算的方式为:先计算指望移动节点的阈值,算法为:(100-(100.0*expected/n.slots.length)).abs,若是计算出的阈值没有超出设置阈值,则不须要为该节点移动slot。只要有一个master的移动节点超过阈值,就会触发rebalance操做。

五、若是触发了rebalance操做。那么就开始执行rebalance操做,先将每一个节点当前分配的slots数量减去指望分配的slot数量得到balance值。将每一个节点的balance从小到大进行排序得到sn数组。

六、用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流程影响不大。

七、获取sn[dst_idx]和sn[src_idx]的balance值较小的那个值,该值即为须要从sn[src_idx]节点迁移到sn[dst_idx]节点的slot数量。

八、接着经过compute_reshard_table方法计算源节点的slot如何分配到源节点列表。这个方法在reshard流程中也有调用,具体步骤能够参考reshard流程的第六步。

九、若是是simulate模式,则只是打印出迁移列表。

十、若是没有设置simulate,则执行move_slot操做,迁移slot,传入的参数为:quiet=>true,:dots=>false,:update=>true。

十一、迁移完成后更新sn[dst_idx]和sn[src_idx]的balance值。若是balance值为0后,游标向前进1。

十二、直到dst_idx到达src_idx游标,完成整个rebalance操做。

 

3.7 add-node将新节点加入集群

 

Usage: redis-trib <command> <options> <arguments ...>                
  add-node        new_host:new_port existing_host:existing_port
                  --slave
                  --master-id <arg>
add-node命令能够将新节点加入集群,节点能够为master,也能够为某个master节点的slave。

add-node有两个可选参数:
--slave:设置该参数,则新节点以slave的角色加入集群
--master-id:这个参数须要设置了--slave才能生效,--master-id用来指定新节点的master节点。若是不设置该参数,则会随机为节点选择master节点。

能够看下add-node命令的执行示例:

$ruby redis-trib.rb add-node --slave --master-id dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.202:6379 10.180.157.199:6379

>>> Adding node 10.180.157.202:6379 to cluster 10.180.157.199:6379

>>> Performing Cluster Check (using node 10.180.157.199:6379)

M: dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.199:6379

   slots:0-5460 (5461 slots) master

   0 additional replica(s)

M: 464d740bf48953ebcf826f4113c86f9db3a9baf3 10.180.157.201:6379

   slots:10923-16383 (5461 slots) master

   0 additional replica(s)

M: befa7e17b4e5f239e519bc74bfef3264a40f96ae 10.180.157.200:6379

   slots:5461-10922 (5462 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 10.180.157.202:6379 to make it join the cluster.

Waiting for the cluster to join.

>>> Configure node as replica of 10.180.157.199:6379.

[OK] New node added correctly.

add-node流程以下:


一、经过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。

二、若是设置了--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返回的结果返回的节点顺序。

三、链接新的节点并与集群第一个节点握手。

四、若是没设置–slave就直接返回ok,设置了–slave,则须要等待确认新节点加入集群,而后执行cluster replicate命令复制master节点。

五、至此,完成了所有的增长节点的流程。

 

3.8 del-node从集群中删除节点

 

Usage: redis-trib <command> <options> <arguments ...>                            
  del-node        host:port node_id

del-node能够把某个节点从集群中删除。del-node只能删除没有分配slot的节点。

del-node执行结果示例以下:

$ruby redis-trib.rb del-node 10.180.157.199:6379 d5f6d1d17426bd564a6e309f32d0f5b96962fe53

>>> Removing node d5f6d1d17426bd564a6e309f32d0f5b96962fe53 from cluster 10.180.157.199:6379

>>> Sending CLUSTER FORGET messages to the cluster...

>>> SHUTDOWN the node.

del-node流程以下:

一、经过load_cluster_info_from_node方法转载集群信息。

二、根据传入的node id获取节点,若是节点没找到,则直接提示错误并退出。

三、若是节点分配的slot不为空,则直接提示错误并退出。

四、遍历集群内的其余节点,执行cluster 
forget命令,从每一个节点中去除该节点。若是删除的节点是master,并且它有slave的话,这些slave会去复制其余master,调用的方法是get_master_with_least_replicas,与add-node没设置--master-id寻找master的方法同样。

五、而后关闭该节点node

 

3.9 set-timeout设置集群节点间心跳链接的超时时间

 

Usage: redis-trib <command> <options> <arguments ...>                            
  set-timeout     host:port milliseconds

set-timeout用来设置集群节点间心跳链接的超时时间,单位是毫秒,不得小于100毫秒,由于100毫秒对于心跳时间来讲过短了。
该命令修改是节点配置参数cluster-node-timeout,默认是15000毫秒。经过该命令,能够给每一个节点设置超时时间,设置的方式使用config set命令动态设置,而后执行config rewrite命令将配置持久化保存到硬盘。
如下是示例:

ruby redis-trib.rb set-timeout 10.180.157.199:6379 30000

>>> Reconfiguring node timeout in every cluster node...

*** New timeout set for 10.180.157.199:6379

*** New timeout set for 10.180.157.205:6379

*** New timeout set for 10.180.157.201:6379

*** New timeout set for 10.180.157.200:6379

*** New timeout set for 10.180.157.208:6379

>>> New node timeout set. 5 OK, 0 ERR.

 

3.10 call在集群所有节点上执行命令

 

Usage: redis-trib <command> <options> <arguments ...>                            
  call            host:port command arg arg .. arg

call命令能够用来在集群的所有节点执行相同的命令。call命令也是须要经过集群的一个节点地址,连上整个集群,而后在集群的每一个节点执行该命令。

$ruby redis-trib.rb call 10.180.157.199:6379 get key

>>> Calling GET key

10.180.157.199:6379: MOVED 12539 10.180.157.201:6379

10.180.157.205:6379: MOVED 12539 10.180.157.201:6379

10.180.157.201:6379:

10.180.157.200:6379: MOVED 12539 10.180.157.201:6379

10.180.157.208:6379: MOVED 12539 10.180.157.201:6379

 

3.11 import将外部redis数据导入集群

 

Usage: redis-trib <command> <options> <arguments ...>                            
  import          host:port
                  --from <arg>
                  --copy
                  --replace

import命令能够把外部的redis节点数据导入集群。导入的流程以下:

一、经过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。
二、链接外部redis节点,若是外部节点开启了cluster_enabled,则提示错误。
三、经过scan命令遍历外部节点,一次获取1000条数据。
四、遍历这些key,计算出key对应的slot。
五、执行migrate命令,源节点是外部节点,目的节点是集群slot对应的节点,若是设置了--copy参数,则传递copy参数,若是设置了--replace,则传递replace参数。
六、不停执行scan命令,直到遍历彻底部的key。
七、至此完成整个迁移流程
这中间若是出现异常,程序就会中止。没使用--copy模式,则能够从新执行import命令,使用--copy的话,最好清空新的集群再导入一次。
 git

import命令更适合离线的把外部redis数据导入,在线导入的话最好使用更专业的导入工具,以slave的方式链接redis节点去同步节点数据应该是更好的方式。github

下面是一个例子redis

./redis-trib.rb import --from 10.0.10.1:6379 10.10.10.1:7000
上面的命令是把 10.0.10.1:6379(redis 2.8)上的数据导入到 10.10.10.1:7000这个节点所在的集群算法

相关文章
相关标签/搜索