3.迁移槽和数据
加入集群后需要为新节点迁移槽和相关数据,槽在迁移过程中集群可以正常提
供读写服务,迁移过程是集群扩容最核心的环节,下面详细讲解。
(1)槽迁移计划
槽是 Redis 集群管理数据的基本单位,首先需要为新节点制定槽的迁移计划,确定原有节点的哪些槽需要迁移到新节点。迁移计划需要确保每个节点负责相似数量的槽,从而保证各节点的数据均匀。例如,在集群中加入 6385 节点,如图所示。加入 6385 节点后,原有节点负责的槽数量从 6380 变为 4096 个。
槽迁移计划确定后开始逐个把槽内数据从源节点迁移到目标节点。
(2)迁移数据
数据迁移过程是逐个槽进行的,每个槽数据迁移的流程如图 10-23 所示。
流程说明:
1)对目标节点发送 cluster setslot{slot}importing{sourceNodeId}命令,让目标节点准备导入槽的数据。
2)对源节点发送 cluster setslot{slot}migrating{targetNodeId}命令,让源节点准备迁出槽的数据。
3)源节点循环执行 cluster getkeysinslot{slot}{count}命令,获取 count 个属于槽{slot}的键。
4)在源节点上执行 migrate{targetIp}{targetPort}""0{timeout}keys{keys...}命令,
把获取的键通过流水线(pipeline)机制批量迁移到目标节点,批量迁移版本的migrate 命令在 Redis3.0.6 以上版本提供,之前的 migrate 命令只能单个键迁移。对于大量 key 的场景,批量键迁移将极大降低节点之间网络 IO 次数。
5)重复执行步骤 3)和步骤 4)直到槽下所有的键值数据迁移到目标节点。
6)向集群内所有主节点发送 cluster setslot{slot}node{targetNodeId}命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽指向新节点。
我们手动使用命令把源节点 6379 负责的槽 4096 迁移到目标节点 6385 中,流程如下:
1) 目标节点准备导入槽 4096 数据:
127.0.0.1:6385>cluster setslot 4096 importing
cfb28ef1deee4e0fa78da86abe5d24566744411e
OK
确认槽 4096 导入状态开启:
127.0.0.1:6385>cluster nodes
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756 127.0.0.1:6385 myself,master - 0 0 7
connected
[4096-<-cfb28ef1deee4e0fa78da86abe5d24566744411e]
...
2) 源节点准备导出槽 4096 数据:
127.0.0.1:6379>cluster setslot 4096 migrating
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
OK
确认槽 4096 导出状态开启:
127.0.0.1:6379>cluster nodes
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0
0 connected
0-5461 [4096->-1a205dd8b2819a00dd1e8b6be40a8e2abe77b756]
...
3) 批量获取槽 4096 对应的键,这里我们获取到 3 个处于该槽的键:
127.0.0.1:6379> cluster getkeysinslot 4096 100
1) "key:test:5028"
2) "key:test:68253"
3) "key:test:79212"
确认这三个键是否存在于源节点:
127.0.0.1:6379>mget key:test:5028 key:test:68253 key:test:79212
1) "value:5028"
2) "value:68253"
3) "value:79212"
批量迁移这 3 个键,migrate 命令保证了每个键迁移过程的原子性:
127.0.0.1:6379>migrate 127.0.0.1 6385 "" 0 5000 keys key:test:5028 key:test:68253
key:test:79212
出于演示目的,我们继续查询这三个键,发现已经不在源节点中,Redis 返
回 ASK 转向错误,ASK 转向负责引导客户端找到数据所在的节点
127.0.0.1:6379> mget key:test:5028 key:test:68253 key:test:79212
(error) ASK 4096 127.0.0.1:6385
通知所有主节点槽 4096 指派给目标节点 6385:
127.0.0.1:6379>cluster setslot 4096 node
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
127.0.0.1:6380>cluster setslot 4096 node
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
127.0.0.1:6381>cluster setslot 4096 node
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
127.0.0.1:6385>cluster setslot 4096 node
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756=
确认源节点 6379 不再负责槽 4096 改为目标节点 6385 负责:
127.0.0.1:6379> cluster nodes
cfb28ef1deee4e0fa78da86abe5d24566744411e 127.0.0.1:6379 myself,master - 0 0 0
connected
0-4095 4097-5461
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756 127.0.0.1:6385 master - 0
1469718011079 7
connected 4096
...
手动执行命令演示槽迁移过程,是为了让读者更好地理解迁移流程,实际操作
时肯定涉及大量槽并且每个槽对应非常多的键。因此 redis-trib 提供了槽重分片功能,命令如下
redis-trib.rb reshard host:port --from <arg> --to <arg> --slots <arg> --yes --
timeout
<arg> --pipeline <arg>
参数说明:
·host:port:必传参数,集群内任意节点地址,用来获取整个集群信息。
·--from:制定源节点的 id,如果有多个源节点,使用逗号分隔,如果是 all 源节
点变为集群内所有主节点,在迁移过程中提示用户输入。
·--to:需要迁移的目标节点的 id,目标节点只能填写一个,在迁移过程中提示用户输入。
·--slots:需要迁移槽的总数量,在迁移过程中提示用户输入。
·--yes:当打印出 reshard 执行计划时,是否需要用户输入 yes 确认后再执行
reshard。
·--timeout:控制每次 migrate 操作的超时时间,默认为 60000 毫秒。
·--pipeline:控制每次批量迁移 […]
我们已经为新节点 6395 迁移了一个槽 4096,剩下的槽数据迁移使用 redistrib.rb 完成,命令如下:
#redis-trib.rb reshard 127.0.0.1:6379
>>> Performing Cluster Check (using node 127.0.0.1:6379)
………
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
打印出集群每个节点信息后,reshard 命令需要确认迁移的槽数量,这里我
们输入 4096 个:
How many slots do you want to move (from 1 to 16384)4096
输入 6385 的节点 ID 作为目标节点,目标节点只能指定一个:
What is the receiving node ID
1a205dd8b2819a00dd1e8b6be40a8e2abe77b756
之后输入源节点的 ID,这里分别输入节点 6379、6380、6381 三个节点 ID
最后用 done 表示结束:
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:cfb28ef1deee4e0fa78da86abe5d24566744411e
Source node #2:8e41673d59c9568aa9d29fb174ce733345b3e8f1
Source node #3:40b8d09d44294d2e23c7c768efc8fcd153446746
Source node #4:done
数据迁移之前会打印出所有的槽从源节点到目标节点的计划,确认计划无误后
输入 yes 执行迁移工作:
Moving slot 0 from cfb28ef1deee4e0fa78da86abe5d24566744411e
....
Do you want to proceed with the proposed reshard plan (yes/no) yes
redis-trib 工具会打印出每个槽迁移的进度。
当所有的槽迁移完成后,reshard 命令自动退出,执行 cluster nodes 命令检查节点和槽映射的变化节点 6385 负责的槽变为:0-136540965462-682610923-12287。由于槽用于hash 运算本身顺序没有意义,因此无须强制要求节点负责槽的顺序性。迁移之后建议使用 redis-trib.rb rebalance 命令检查节点之间槽的均衡性。命令如下:
# redis-trib.rb rebalance 127.0.0.1:6380
>>> Performing Cluster Check (using node 127.0.0.1:6380)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** No rebalancing needed! All nodes are within the 2.0% threshold.
可以看出迁移之后所有主节点负责的槽数量差异在 2%以内,因此集群节点数据
相对均匀,无需调整。