上一篇文章教大家手动搭建了一个Cluster集群,并演示了故障转移的过程,本文接着讲Cluster集群的动态扩展,简单来讲就是如何在Cluster模式下实现节点的新增和废弃节点的删除以及如何重新分配slot来达到集群的高可用,实现集群的动态扩展,而这一切都基于redis-trib.rb脚本,首先,我们对redis-trib.rb的命令开始说起:
本文分两部分:1,redis-trib.rb 常用命令介绍 2.命令演示
1.redis-trib.rb 常用命令介绍
可以使用 redis-trib.rb help 查看说明文档
redis-trib.rb常用命令帮助图解
常用命令使用演示
1.创建集群
命令格式:redis-trib.rb create --replicas n [host:port,...]
--replicas参数指定集群中每个主节点配备n从节点。
备注:如果创建集群时,单节点的数据库文件包含slot数据(例如nodes.7000.conf包含其他节点配置信息或者dump.7000.rdb包含0~16384某个slot的数据),集群会创建失败。所有节点的配置文件和上文(redis专题系列17 -- redis 集群模式之Cluster集群)提到的一样.
示例:
先依次启动要加入集群的节点,然后创建集群,我把这些命令放在了 batch.bat 脚本中执行,然后把batch.bat放到redis安装目录下
脚本命令
将脚本文件 batch.bat 放到 redis安装目录下
创建集群窗口日志:
设置分配的集群信息,输入yes
为主节点分配 16384 个slots
关于主从节点的选择及槽的分配,其算法如下:
1> 把节点按照host分类,这样保证master节点能分配到更多的主机中。
2> 遍历host列表,从每个host列表中弹出一个节点,放入interleaved数组。直到所有的节点都弹出为止。
3> 将interleaved数组中前master个数量的节点保存到masters数组中。
4> 计算每个master节点负责的slot数量,16384除以master数量取整,这里记为N。
5> 遍历masters数组,每个master分配N个slot,最后一个master,分配剩下的slot。
6> 接下来为master分配slave,分配算法会尽量保证master和slave节点不在同一台主机上。对于分配完指定slave数量的节点,还有多余的节点,也会为这些节点寻找master。分配算法会遍历两次masters数组。
7> 第一次遍历master数组,在余下的节点列表找到replicas数量个slave。每个slave为第一个和master节点host不一样的节点,如果没有不一样的节点,则直接取出余下列表的第一个节点。
8> 第二次遍历是分配节点数除以replicas不为整数而多出的一部分节点。
2.检查/校验集群状态
命令格式:redis-trib.rb check 任意节点h:p
示例:
3.查看集群信息
命令格式:redis-trib.rb info 任意节点h:p
示例:
4.修复单节点
命令格式:redis-trib.rb fix 故障节点h:p
目前fix命令能修复两种异常,
1. 节点中存在处于迁移中(importing或migrating状态)的slot。
2. 节点中存在未分配的slot。
其他异常不能修复。
示例:
5.在线迁移slot
交互环境中使用
命令格式: redis-trib.rb reshard 节点h:p
提示分配多少槽点?我输入了1000
询问这1000个slots要分到哪个节点,分到7002,输入7002的id
如果你不知带7002的节点id是多少,可以去看log中的记录,或者使用前面的命名info , check,或者去看日志nodes.7002.conf. 示例中7002节点对应的id为:
24789385e9540dca53f853e836c6d1dd8c26aba8
输入接受这1000个slots的节点id,接着会询问你源节点(即要移动哪个节点的1000 slots到7002节点上),我们选择节点7001(如果想从其他的节点平均分配到7002,可以输入all),id为
a796e7ea80024a3dfb88df25ead248454638a907,接着输入done,trib为我们生成分配计划
输入yes,执行slots分配计划,看到7001的节点5461~6460共1000个slots分配到7002。
此时查看slots分配状况:
此时7001的1000个slots被移动到7002节点上
下面我们再演示一下all的情形,分配200个节点到7000上:
输入all
此时集群slots的分配状况为:
7000的slots从5461->5661(成功的增加200 slots),7001 slots 6461 ->6342(减少了120 slots),7002 slots 从4462->4381(减少了80 slots),trib根据7001和7002的slots数量按照比例共分配了200个slots到7000上,即 7001应分配的slots数量为 200*(6461/(6461+4462))=120,剩下的(200-120=80)slots由7002提供,所有的slots迁移都是由小到大。
完整命令:
redis-trib.rb reshard host:port --from
其中,
host:port:必传参数,集群内任意节点地址,用来获取整个集群信息。
--from:源节点id,如果有多个源节点,使用逗号分隔,如果是all,则源节点为集群内出目标节点外的其它所有主节点。
--to:目标节点id,只能填写一个。
--slots:需要迁移槽的总数量。
--yes:迁移无需用户手动确认。
--timeout:控制每次migrate操作的超时时间,默认为60000毫秒。
--pipeline:控制每次批量迁移键的数量,默认为10。
如,
redis-trib.rb reshard --from a8b3d0f9b12d63dab3b7337d602245d96dd55844 --to f413fb7e6460308b17cdb71442798e1341b56cbc --slots 10923 --yes --pipeline 20 127.0.0.1:6383
6.平衡集群节点slot数量
我们知道,假设由于reshard造成单点的slots数量过多,那么对应的其key命中率就越高,访问压力就过大,这个节点就会成为集群中的瓶颈。那么,rebalance可以很好的为我们解决这个问题。
命令格式:
rebalance host:port
--weight
--auto-weights
--use-empty-masters
--timeout
--simulate
--pipeline
--threshold
参数释义:
--weight
--auto-weights:自动将每个节点的权重默认为1。如果--weight和--auto-weights同时指定,则--auto-weights会覆盖前者。
--threshold
--use-empty-masters:默认没有分配slot节点的master是不参与rebalance的。如果要让其参与rebalance,需添加该参数。
--timeout
--simulate:设置该参数,只会提示用户会迁移哪些slots,而不会执行真正的迁移操作。
--pipeline
示例:
命令:
redis-trib.rb rebalance --weight a796e7ea80024a3dfb88df25ead248454638a907=3 --weight 24789385e9540dca53f853e836c6d1dd8c26aba8=4 --use-empty-masters 127.0.0.1:7001
然后redis集群会执行平衡计划,移动slots多的节点到少的节点,每一个跳动的#号就代表一个移动中的slot.
此时集群就会按照权重调整不同节点对应的slots数量,rebalance后的slots数量为:
按照权重比例分配slots数量
7.删除节点
语法:redis-trib.rb del-node host:port node_id
在删除节点之前,其对应的槽必须为空,所以,在进行节点删除动作之前,必须使用redis-trib.rb reshard将其迁移出去。
slots不为空则无法移除
需要注意的是,如果某个节点的槽被完全迁移出去,其对应的slave也会随着更新,指向迁移的目标节点。
示例:
删除节点7000
原来的7000的从节点7003成为了7002的从节点
8.添加新节点
命令格式:redis-trib add-node new_host:new_port
existing_host:existing_port --slave --master-id
new_host:new_port:待添加的节点,必须确保其为空或不在其它集群中。否则,会提示以下错误。
[ERR] Node 127.0.0.1:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
所以,线上建议使用redis-trib.rb添加新节点,因为其会对新节点的状态进行检查。如果手动使用cluster meet命令加入已经存在于其它集群的节点,会造成被加入节点的集群合并到现有集群的情况,从而造成数据丢失和错乱,后果非常严重,线上谨慎操作。
existing_host:existing_port:集群中任意一个节点的地址。
如果添加的是主节点,只需指定源节点和目标节点的地址即可。
添加主节点
如果添加的是从节点,其语法如下
redis-trib.rb add-node --slave --master-id f413fb7e6460308b17cdb71442798e1341b56cbc 127.0.0.1:6379 127.0.0.1:6384
注意:--slave和--master-id必须写在前面
9.设置节点的超时时间
redis-trib.rb set-timeout host:port milliseconds
其实就是批量修改集群各节点的cluster-node-timeout参数。
10.在集群所有节点上执行命令
格式:
redis-trib.rb call host:port command arg arg .. arg
示例:
11.将外部redis数据导入集群
redis-trib.rb import --from 127.0.0.1:7000 127.0.0.1:7001
其内部处理流程如下:
1> 通过
load_cluster_info_from_node方法加载集群信息,check_cluster方法检查集群是否健康。
2> 连接外部redis节点,如果外部节点开启了cluster_enabled,则提示错误([ERR] The source node should not be a cluster node.)
3> 通过scan命令遍历外部节点,一次获取1000条数据。
4> 遍历这些key,计算出key对应的slot。
5> 执行migrate命令,源节点是外部节点,目的节点是集群slot对应的节点,如果设置了--copy参数,则传递copy参数,其会保留源节点的key,如果设置了--replace,则传递replace参数。如果目标节点中存在同名key,其值会被覆盖。两个参数可同时指定。
6> 不停执行scan命令,直到遍历完所有key。
7> 迁移完成。
示例:
从单节点redis导入到集群,sourceNode不能是集群中的节点
OK,redis-trib.rb相关命令到此为止,下面针对cluster集群就轻而易举了。
补充:redis5.0之后,有关集群的相关命令集成到了redis-cli中,查看相关命令redis-cli --cluster help.