在redis cluster集群中,不可避免的会出现数据不平衡的情况,为了平衡各节点的压力,就需要对集群做节点平衡处理,将数据从负载较高的节点迁移到负载低的节点.
代码语言:javascript复制redis-trib.rb rebalance 127.0.0.1:6379
当集群中新加入节点时,也需要对数据做迁移处理.
代码语言:javascript复制redis-trib.rb reshard --from all --to xxx --slots 110 127.0.0.1:6379
下面就一起看下hash槽迁移的过程.
槽迁移
在使用redis-trib.rb做rebalance和reshard进行节点迁移的时候,都会调用move_slot()方法进行数据数据和hash槽迁移.
通过方法可以了解具体迁移步骤
1.将迁移目标节点设置为importing状态
代码语言:javascript复制CLUSTER SETSLOT slot IMPORTING node
2.将迁移源节点设置为migrating状态
代码语言:javascript复制CLUSTER SETSLOT slot MIGRATING node
3.从源节点中取出槽对应部分key
代码语言:javascript复制CLUSTER GETKEYSINSLOT slot count
4.将取出的key写入目标节点
代码语言:javascript复制MIGRATE 192.168.1.34 6379 "" 0 5000 KEYS key1 key2 key3
5.重复上述3和4两步骤,直到数据迁移完毕
6.通知所有节点hash槽变化,并退出importing或migrating
代码语言:javascript复制CLUSTER SETSLOT slot NODE node
7.如果想取消hash槽迁移动作可以执行以下命令
代码语言:javascript复制CLUSTER SETSLOT slot stable
move_slot()方法主要逻辑如下:
代码语言:javascript复制def move_slot(source,target,slot,o={})
...
if !o[:cold]
target.r.cluster("setslot",slot,"importing",source.info[:name])
source.r.cluster("setslot",slot,"migrating",target.info[:name])
end
# Migrate all the keys from source to target using the MIGRATE command
while true
keys = source.r.cluster("getkeysinslot",slot,o[:pipeline])
break if keys.length == 0
begin
source.r.client.call(["migrate",target.info[:host],target.info[:port],"",0,@timeout,:keys,*keys])
rescue => e
if o[:fix] && e.to_s =~ /BUSYKEY/
xputs "*** Target key exists. Replacing it for FIX."
source.r.client.call(["migrate",target.info[:host],target.info[:port],"",0,@timeout,:replace,:keys,*keys])
else
puts ""
xputs "[ERR] Calling MIGRATE: #{e}"
exit 1
end
end
print "."*keys.length if o[:dots]
STDOUT.flush
end
puts if !o[:quiet]
# Set the new node as the owner of the slot in all the known nodes.
if !o[:cold]
@nodes.each{|n|
next if n.has_flag?("slave")
n.r.cluster("setslot",slot,"node",target.info[:name])
}
end
....
end
Smart客户端
符合Redis的Smart客户端会在内部维护hash槽与节点的映射关系.
客户端在发送请求时,会先根据CRC16(key)384计算key对应的hash槽,通过映射关系,本地就可实现键到节点的查找,从而保证IO效率的最大化.
但如果出现故障转移或者hash槽迁移时,这个映射关系是如何维护的呢?
Moved
当对应的hash槽已经迁移到变的节点时,
1. Redis cluster会返回给客户端一个moved错误, 并告诉节点这个hash槽迁移后的节点IP和端口是多少
2. 客户端接受到moved错误时,会更新本地的映射关系
3. 客户端向新节点发送请求命令
Ask
如果hash槽是在迁移中时,发生的请求呢?
1. 源节点接收到请求后,会先判断这个key是否还在源节点,则返回请求结果
2. 如果key不在源节点时,会返回ask错误,并返回目标节点的IP和端口
3. 客户端向迁移目标节点,首先发送asking命令,再发送数据相关请求命令
4. 客户端在收到ask错误时,并不会更新本地槽与节点的映射关系
ask与moved可以简单的理解为hash槽的临时重定向和永久重定向.