Redis Cluster 槽迁移与Smart客户端

2022-06-20 19:56:57 浏览数 (1)

在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槽的临时重定向和永久重定向.

0 人点赞