【1】架构
software:redis6.2.4 OS:CentOs7.9
192.168.191.176 redis:6381/6382
192.168.191.211 redis:6383/6384
192.168.191.70 redis:6385/6386
192.168.191.82 redis:6387/6388
【2】构建集群
【2.1】创建集群
一主一从对应,集群一共是3主3从
redis-cli --cluster create 192.168.191.176:6381 192.168.191.176:6382 192.168.191.211:6383 192.168.191.211:6384 192.168.191.70:6385 192.168.191.70:6386 -a 123456 --cluster-replicas 1
【2.2】登录查看
-c: 登录访问节点所在集群
redis-cli -c -h 192.168.191.176 -p 6381 -a 123456
我们可以看到,get set 会自动分槽去各个节点,且我们访问的节点也会随之变化
【2.3】检查集群状态
redis-cli --cluster check 192.168.191.176:6381 -a 123456A
ok
【3】集群创建操作
【3.1】命令汇总
(1)集群创建: redis-cli --cluster create node1_ip:port node2_ip:port .... node6_ip:port --cluster-replicas 1 <1> --cluster create:集群创建命令 <2>--cluster-replicas: 配置该集群每个主库只有1个从节点,不写该参数默认全部为主节点 (2)连接集群 reds-cli -c -h any_nodeip -p the_node_port -a password (3)检查集群状态 redis-cli --cluster check
【3.1】迁移 随机hash slot
(1)交互式
连接到集群,进行 reshard
redis-cli --cluster reshard 192.168.191.176:6381 -a 123456
A
我们可以看到,交互式迁移会问我们,要迁移哪些hash槽,谁接收,源节点是哪些
这里我们输入源节点:b249c86b5817037411154898e8458eddde1ab5b0
然后输入done;
(2)代码式自动化分片
一般形式:
redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
--cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔,也可以使用 all 表示所有节点
--cluster-to:表示需要新分配节点的node ID(每次只能分配一个)
--cluster-slots:分配的slot数量
--cluster-yes: 直接同意迁移shared计划,不用回显到屏幕上
实操案例:
redis-cli --cluster reshard 192.168.191.176:6381
--cluster-from b249c86b5817037411154898e8458eddde1ab5b0
--cluster-to a68dad4f4e53dccc65d65985eb38ca30c77c3dfb
--cluster-slots 1
--cluster-yes
-a 123456
如上图我们可以发现,把3010 槽位 从源节点迁移到了目标节点
(3)自动平衡
自动把新增的主节点,由其他节点自动平衡分配
redis-cli --cluster rebalance --cluster-use-empty-masters 192.168.191.176:6381
【3.2】增删节点
(1)增加从节点
一般形式:
增加从节点在集群:随机跟一个主节点
redis-cli --cluster add-node new_add_ip:port clusterNode_ip:port --cluster-slave
增加从节点在集群:指定某个主节点
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id target_masterNode_id
案例:
redis-cli --cluster add-node 192.168.191.82:6387 192.168.191.176:6381 --cluster-slave -a 123456
注意,新加的从节点如果没有指定主节点,那么它是去一个副本数更少的主节点做副本;如果副本数都一样,那么就随机跟一个主节点;
如下图:
如上图,我们可以看到新节点 192.168.191.82:6387 加入了集群,且作为 6383实例的副本
(2)增加主节点
一般形式:
redis-cli --cluster add-node new_ip:port clusterNode_ip:port
案例:
redis-cli --cluster add-node 192.168.191.82:6388 192.168.191.176:6381 -a 123456
注意,新增的节点是没有 hash slots 的,需要用【3】中的办法,迁移 hash slots 到新节点过来;
迁移 100个 slots 到这个主节点,命令如下:这里就不详细介绍了;
redis-cli --cluster check 192.168.191.176:6381 -a 123456
redis-cli --cluster reshard 192.168.191.176:6381 -a 123456 --cluster-from all --cluster-to a9b60e95b1487b177b0e58751d201ac1b773974b --cluster-slots 100 --cluster-yes
【3.3】删除节点
(0)快速结论
如果删除后,其它节点还看得到这个被删除的节点,则可通过FORGET命令解决,需要在所有还看得到的其它节点上执行:
CLUSTER FORGET `<node-id>`
(1)删除从节点
一般形式:
redis-cli --cluster 迁移
del-node clusterNode_ip:port deleteNode_id -a 123456
案例:
删掉6387从节点
redis-cli --cluster check 192.168.191.176:6381 -a 123456
redis-cli --cluster del-node 192.168.191.176:6381 ae1fe28ee59f9a0e5d316f1f8195d04cc1a7be36 -a 123456
如上图所示,最后我们check的时候,已经看不到 6387节点
注意:当被删除掉的节点重新起来之后不能自动加入集群,但其和主的复制还是正常的,也可以通过该节点看到集群信息(通过其他正常节点已经看不到该被del-node节点的信息)。
如果想要再次加入集群,则需要先在该节点执行cluster reset,再用add-node进行添加,进行增量同步复制。
(2)删除主节点
一般形式:
redis-cli --cluster del-node clusterNode_ip:port deleteNode_id -a 123456
案例:(注意必须要清空主节点的 hash slots 才能删除)
从集群删掉端口为 6388 的主节点:
redis-cli --cluster del-node 192.168.191.176:6381 a9b60e95b1487b177b0e58751d201ac1b773974b -a 123456
很明显报错了,必须要清空主节点的 hash slots 才能删除;清空 hash slots 如下:
redis-cli --cluster reshard 192.168.191.176:6381 -a 123456 --cluster-from a9b60e95b1487b177b0e58751d201ac1b773974b --cluster-to b249c86b5817037411154898e8458eddde1ab5b0 --cluster-slots 100 --cluster-yes
操作完后,居然报错了(为什么报错,因为只有99个槽,我们居然写迁移了100个):无需理会
Node 192.168.191.82:6388 replied with error:
ERR Please use SETSLOT only with masters.
------------------------------ 只是参考,建议使用,但本案例未使用------------------------------------- 其他方式参考:利用 rebalance 来删除主节点 (rebalance 平均把 hash slot 分配到其他主节点上去): redis-cli -a 123456 --cluster rebalance --cluster-weight 11ac5cf5004f22a55ee0afa2b221d120ad768f7d=1 f5dc23c602b57f6b09b4909d01289ff4d80220ed=1 4ba0958a0c9aa944962182673058fbc4c27952eb=1 4dfde05a131e9b8900553ef03ef41703737e449f=0 192.168.191.176:6381 注意,无论任何形式,如果把主节点的 slot 都迁移走了,那么该主节点下的从库会自动转移到其他有 slot 的主节点去 ------------------------------ 只是参考,建议使用,但本案例未使用-------------------------------------
我们对比一下:
操作前:
操作后:居然自动变成了从库
再次删,可以了
【3.4】副本迁移
在目标slave上执行,命令格式:(登录上节点后)
cluster replicate <master-node-id>
案例:(或者也可以用 redis-cli 形式打命令)
将 6388 的 0 槽位主节点 变成从节点(使用命令cluster replicate,参数为master节点ID,注意不是IP和端口,在被迁移的slave上执行该命令。)
redis-cli -h 192.168.191.82 -p 6388 -a 123456 cluster replicate a68dad4f4e53dccc65d65985eb38ca30c77c3dfb
【4】故障转移测试
【4.1】自动故障转移
(1)手动正常关闭某个主节点
操作前:构造 a b c key
可以看到 a 是存放在 6385 、b是存放在 6381 、c 是存放在 6383
然后查看集群架构
操作模拟故障:关闭6381
redis-cli -h 192.168.191.176 -p 6381 -a 123456 shutdown
操作后:我们可以看到 6386 实例已经由从变成主
key 的情况
我们发现 key 是都在的,都可以查,证明是正常的;
且我们发现key的位置,对比之前
故障转移前 a b c key:a 是存放在 6385 、b是存放在 6381 、c 是存放在 6383
故障转移后 b b c key:a 是存放在 6385 、b是存放在 6384 、c 是存放在 6383
而之前 6384 正好是 6381 的从库,且Get set 命令均没有问题;
所以自动故障转移成功(注意,实例关闭无法访问引起的自动故障转移的话,会引起当前已经连接上这个实例的链接全部断开)
【4.2】手动故障转移
我们手动故障转移试试:
操作前:
6381是从,6384 是 6381 的主,我们手动故障转移,把 6381和 6384主从互换
操作:redis-cli -c -h 192.168.191.176 -p 6381 -a 123456 cluster failover
操作后:主从互换了
连接验证:连接并没有什么问题不会因为切换而中断重连之类的
【4.3】关闭没有从库副本的主库(关闭一整套主从)
看看会是什么样
操作前:
操作:关闭没有副本的 6384 实例
redis-cli -h 192.168.191.211 -p 6384 -a 123456 shutdown
操作后:
我们可以发现,报错了,说不是所有的 hash slot 都是可用的;
用 cluster info 发现 状态也变成了失败,然后失败的 slots 正好是 我们 6384 中占用的 slots 数量 2535 个;
然后我们发现整个集群处于无法访问状态了,无法读写;
因为我们设置了集群参数:cluster-require-full-coverage yes
# --当为no时: 如果请求过来发现集群无法处理(比如某个主实例挂了又没有副本顶上,造成缺失部分hash槽),则可以重新分配hash槽 覆盖原有数据;
# --当为yes时:则必须所有hash槽 ok 状态集群才能访问
重新启动 6384 实例:
又可以用了,也可以 get set 了
【5】集群增删改+迁移slot > 手动命令操作集群
【5.0】命令汇总
(1)变更主从关系(在目标slave上执行,命令格式:) cluster replicate <master-node-id> =》
# 外部直接执行
redis-cli -h 192.168.0.251 -p 6381 cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 再次注意:使用命令cluster replicate,参数为master节点ID,注意不是IP和端口,在被迁移的slave上执行该命令。 (2)slots相关命令 cluster addslots slot1 [slot2] ... [slotn] cluster delslots slot1 [slot2] ... [slotn] cluster setslot slot node des-node-id cluster setslot slot migrating node cluster setslot slot importing node =》 addslots:redis-cli -h 192.168.135.173 -p 7001 cluster addslots {0..5461} migrating:迁移 在源节点a上执行:cluster setslot 8 migrating dst-b-node-id importing:在目标节点b上执行:cluster setslot 8 importing src-a-node-id
上述导入、迁移操作只是将slot标记为迁移状态,完成迁移还需要执行(在目标node上执行): slot NODE:实际迁移 =》 CLUSTER SETSLOT <slot> NODE <dst-node-id> delslots:删除指定槽位:redis-cli -c -h 172.21.205.85 -p 8201 cluster delslots 747 迁移案例:(没数据可以,有数据的话会丢失 Key) # 将值为11677的slot迁到192.168.31.3:6379 $ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 IMPORTING 216e0069af11eca91465394b2ad7bf1c27f5f7fe OK
$ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 NODE 4e149c72aff2b6651370ead476dd70c8cf9e3e3c OK 取消迁移使用“CLUSTER SETSLOT <slot> STABLE” (3)从集群删除节点 集群命令: CLUSTER FORGET <node-id> 被删除节点重置 hash 槽 命令: flushdb (如果有key) CLUSTER RESET SOFT
【5.1】meet 加入集群案例
我们可以看到下图,加入节点其实就是发送了
cluster meet 192.168.191.82:6387
【6】集群参数验证
【6.0】参数
#cluster cluster-enabled yes #-- 允许实例加入集群 cluster-config-file nodes-${port}.conf #-- 每个加入群集的实例都会有一个,持久化的记录节点状态变化等信息 cluster-node-timeout 15000 #-- ms,节点响应超时,影响主从故障转移,影响网络分区主不可写入时间 cluster-replica-validity-factor 10 #-- 这个系数是 超时事件* 它 + 集群心跳检查时间;例如:假设 A=cluster-node-timeout=30,B=cluster-replica-validity-factor=10,C=repl-ping=10,则 A*B+C = 30*10+10 = 310秒; # 与主库断开310秒的从库不参与故障转移 cluster-require-full-coverage yes # --当为no时: 如果请求过来发现集群无法处理(比如某个主实例挂了又没有副本顶上,造成缺失部分hash槽),则可以重新分配hash槽 覆盖原有数据; yes 则必须所有hash槽 ok 状态集群才能访问 cluster-migration-barrier 1 # -- 迁移壁垒,即当某个主实例下没有副本,同时又有某个主实例下有超过1个以上的副本,则至少保留一个副本,多的则可以迁移到没有副本的实例下做副本 cluster-replica-no-failover no # -- 副本是否故障转移,如果为 yes 则副本无法顶替主实例自动故障转移(可以手动) cluster-allow-reads-when-down no # --6.0参数,当集群不可用时,是否允许集群读访问(为 yes 时,只能对现有 key 读,但不能增删查改)
【6.1】副本迁移(cluster-migration-barrier 1,默认1)
参数:cluster-migration-barrier 1
# -- 迁移壁垒,即当某个主实例下没有副本,同时又有某个主实例下有超过1个以上的副本,则至少保留1个副本,多的则可以迁移到没有副本的实例下做副本
先给 6381 主节点 增加2个从节点 6387 6388 ;
redis-cli --cluster add-node 192.168.191.82:6387 192.168.191.176:6381 --cluster-slave --cluster-master-id b249c86b5817037411154898e8458eddde1ab5b0 -a 123456
redis-cli --cluster add-node 192.168.191.82:6388 192.168.191.176:6381 --cluster-slave --cluster-master-id b249c86b5817037411154898e8458eddde1ab5b0 -a 123456
我们可以看到,6381 它现在有3个从库
同时我们可以发现另外的一个主库 6385,6382是 6385的从库;
这个时候我们关闭 6382 试试,然后等一会儿看看会不会有某一个从库自动变成 6385 的从库
redis-cli -h 192.168.191.176 -p 6382 -a 123456 shutdown
如下图:
关了之后我们发现,第一次查询:主库 6385 从库 6382 是断开连接状态
过了几秒再查一次,发现 6388 跑了过来,自动变成了 6385 的从库,证明这个参数确实有效
【6.2】集群不可用时允许读(cluster-allow-reads-when-down yes,默认no)
cluster-allow-reads-when-down no
# --6.0参数,当集群不可用时,是否允许集群读访问
操作前:
我们发现 a,d,e 都在 6385
操作:关闭 6385 主节点
redis-cli -a 123456 -p 6385 -h 192.168.191.70 shutdown
那么故障转移后,从节点 6382 接替了 6385,a,d,e 自然也就在 6382上
这个时候有连接(无论是本身连接还是集群连接)连在 6385 的话 直接被自动断开,需要重连集群
操作:关闭没有副本的主节点 6382
操作后:check 集群架构和状态
操作后:检阅key 是否可以读写
如下图:
我们可以发现
(1)如下图:第一次连接时,如果你直接去访问的 key 在已经失去连接的 cluster node 上的话,那么就会失败,且会尝试那个链接,你整个连接都丢失了
(2)如上图,第二次连接时,我们直接访问不在 失去连接的 cluster node 上的 key时,现有key是可以访问的;只能读,不能修改、删除、新建;
这个和我们之前集群状态有问题后,直接报错 是不一样的,该 参数 cluster-allow-reads-when-down 为 no 时 访问结果如下图
【6.3】副本有效因子(cluster-replica-validity-factor 2,默认10)
cluster-replica-validity-factor 10
#-- 这个系数是 超时事件* 它 + 集群心跳检查时间;例如:假设 A=cluster-node-timeout=30,B=cluster-replica-validity-factor=10,C=repl-ping=10,则 A*B+C = 30*10+10 = 310秒;
# 与主库断开310秒的从库不参与故障转移,如果为0则永远有效
操作前:
操作:我们继续操作 6382 和 6382 这对主从,我们已经把
(1) cluster-replica-validity-factor 设置成2,集群超时事件为 15S,那么按道理等40S,它就不会被故障转移了;
(2)从库 6385 断开主从
操作前:
操作:直接 在 6385(从副本实例) 上 slaveof no one ,结果如下:报错,不然执行
192.168.191.70:6385> slaveof no one (error) ERR REPLICAOF not allowed in cluster mode. 192.168.191.70:6385> info replication
操作:设置防火墙,然后 6382 和 6385 无法通信
iptables -I INPUT -p tcp --dport 6382 -s 192.168.191.70 -j DROP
如下图,我们已经断开200多秒了;
操作:关闭 6382(主库)试试,看是否会自动故障转移到从库
操作后:确实不会故障转移
【6.4】所有槽位都可用才可以访问集群(cluster-require-full-coverage no,默认为yes)
集群参数:cluster-require-full-coverage yes
# --当为no时: 如果请求过来发现集群无法处理(比如某个主实例挂了又没有副本顶上,造成缺失部分hash槽),则可以重新分配hash槽 覆盖原有数据;
# --当为yes时:则必须所有hash槽 ok 状态集群才能访问
我们在【4.3】中就实验过 该参数为 yes的情况
cluster-require-full-coverage no
cluster-allow-reads-when-down yes
这次我们试试 为 no的情况
操作前:
操作:老样子,我们把 6385 和 6382 都关闭
操作后:
如下图:我们可以发现,未丢失节点的槽位依然是可以使用的,可以 GET 的;
和参数 cluster-allow-reads-when-down 有点像,但区别是:
cluster-allow-reads-when-down yes 是集群不可用时 =》只能对现有key读,增删改是不可以的
cluster-require-full-coverage no 是集群不可用时=》可以对现有node存在的key 读写,也可以对新 Key进行 读写
注意,一般正常情况
【7】常见运维命令
(1)集群状态
cluster info 集群信息 cluster nodes 所有节点和slot分布 cluster slots 所有节点和slot分布,可以看出哪些槽位被使用了 cluster slaves <node_id> 返回一个master节点的slaves 列表 redis-cli --cluster check 172.21.205.85:8001 :检查和查看槽位数量及分布
cluster count-failure-reports :查看指定节点错误数
概念:
返回指定节点的故障报告个数,它是Redis Cluster用来使节点的PFAIL状态(这意味着节点不可达节点心跳检查超时)晋升到FAIL状态而的方式;
这意味着集群中大多数的主节点在一个事件 窗口内同意该节点不可达
错误报告来源:
一个节点不可达时间超过 Redis Cluster 配置中的超时时间,这个节点会被其他节点用PFAIL标记。
每当一个节点处理来自其他节点的流言(gossip)包时,这个个节点都会建立故障报告(如果需要会刷新TTL),并且会记住发送消息包的节点所认为处于PFAIL状态下的其他节点。
每个故障报告的生存时间是节点超时时间的两倍。
如果在一段给定的事件内,一个节点被另一个节点标记为PFAIL状态,并且在相同的时间内收到了其他大多数主节点关于该节点的故障报告(如果该节点是主节点包括它自己)。
那么该节点的故障状态会从PFAIL晋升为FAIL,并且会广播一个消息,强制所有可达的节点将该节点标记为FAIL。
案例:redis-cli -c -h 192.168.191.176 -p 6381 cluster count-failure-reports a56b7ef6fbd832398cca527f50029e6efe500e5c
(2)集群:槽位与key的关系
get key :可以查看到 key 所在的节点、槽位具体指
cluster keyslot <key> 获得key对应的槽
cluster countkeysinslot <slot> 返回slot目前包含的key数量。
cluster getkeysinslot <slot> <count> 返回 count个slot 槽中的键。
(3)集群操作
cluster meet <ip> <port> 添加指定的节点到集群,默认成为maser,相当于redis-trib.rb add-node
cluster forget <node-id> 删除指定的节点,相当于redis-trib.rb del-node
cluster replicate <node-id> 将当前节点设置为指定node-id的slave;
cluster saveconfig 将节点信息保存在nodes-6379.conf文化中;
cluster addslots <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
cluster delslots <slot> [slot ...] 移除一个或多个槽对当前节点点。
cluster flushslots 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。注意如果有数据 则 flushdb 或 flushall 后再用 否则无法操作
(4)集群 无key/有key slot 迁移
cluster setslot <slot> node <des_node_id> 将槽 slot 指派给 node_id 指定的节点。
cluster setslot <slot> migrating <des_node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot <slot> importing <source_node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot <slot> stable 取消对槽 slot 的导入(import)或者迁移(migrate)。
迁移案例:
# 将 192.168.31.1 值为11677的 slot 迁到192.168.31.3:6379(注意,slot中有 key 的 千万不要这样做!会丢失key) $ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 IMPORTING <source_node_id> $ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 NODE <des_node_id> 直接这样不行,会丢失 key
有 key 的 slot 迁移
案例演示(slot 中 Key 数量少):迁移 3168 slot
(1)登录 source_node: cluster setslot 3168 migrating desc_node_id
(2)登录 desc_node: cluster setslot 3168 importing source_node_id
(3)登录 source_node: cluster getkeysinslot 3168 =》得到只有一个 key f
(4)登录 source_node: migrate 192.168.191.211 6383 "f" 0 30 copy auth 123456
(5)登录 desc_node: cluster setslot 3168 node desc_node_ip
(6)登录 source_node: cluster setslot 3168 node desc_node_ip
(5)修复集群槽
redis-cli --cluster fix nodeip:port :修复集群槽,解决有主从离开导致非所有槽可用
(6)集群节点软重置、硬重置
cluster reset soft/hard :集群节点软重置、硬重置,软重置可以不用重启在线恢复一个集群节点刚启动的状态,有利于清空该节点群集状态,重新加入集群
【8】深入迁移 slot 原理
在扩展集群时,新增节点是没有 slot 的,那么为了水平扩展是需要其他节点迁移 slot 过来,一个 slot 可能包含了许许多多的 key;
迁移slot过程图:扩容(缩容也一样)
当一个请求(这里说的请求都是正在扩容中的分片的请求)过来之后集群不知道老的数据有没有被移动新的Redis,所以集群会统一先将请求路由到老的Redis。
这个时候就会出现下面四种情况:
A. 数据存在Redis1中,并且没有在移动=》
和非扩容流程一样,Redis1直接返回请求结果给代理,代理返回给客户端,流程结束。
B. 数据存在Redis1中,正在往Redis2中迁移=》
这个时候Redis1会阻塞针对此KEY的访问(针对此Redis的请求都被阻塞了)。待迁移操作完成之后走到下面的流程C。
C. 数据不存在Redis1中,已经被移动到Redis2中。
这个时候Redis1会返回ASKED错误,错误信息中包含Redis2的地址。代理转而将请求发往Redis2。
这个时候路由信息还没有更新,Redis2也是不认这个请求的,针对这种情况集群会在发送正常请求之前发送一个ASKING消息;
Redis2接收到ASKING消息之后会将接下来的一个请求数据认为是自己的。
处理完之后Redis2返回结果给代理,流程结束。
D. 数据不存在Redis1中,也不存在Redis2中
处理逻辑同C。
【8.1】迁移 slot(基于数量,不丢数据)
数据可以被迁移过来
(1)从A迁移到B
这就不细讲了,见【3】
redis-cli --cluster reshard 192.168.191.176:6381 -a 123456
--cluster-from a9b60e95b1487b177b0e58751d201ac1b773974b
--cluster-to b249c86b5817037411154898e8458eddde1ab5b0
--cluster-slots 100 --cluster-yes
(2)自动平衡迁移
然后我发现它一直卡在 0 slot 位置,如上图;
检查集群状态,如下图:
实际检查是否有在迁移:
(方法1)dbsize:查看当前 db 的 key 数量(登录到迁移或被迁移的实例上操作)
(方法2)cluster countkeysinslot 0 :查看槽位中的 key 数量(登录到迁移或被迁移的实例上操作)
【8.2】slot 迁移指定 slot(基于特定值,丢数据)
注意,这种方式迁移数据会丢失;适合空 slot
(1)迁移一个 slot 0(登录 dest 实例操作)
# 将 192.168.31.1 值为11677的 slot 迁到192.168.31.3:6379(注意,slot中有 key 的 千万不要这样做!会丢失key)
$ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 IMPORTING <source_node_id>
$ redis-cli -c -h 192.168.31.3 -p 6379 CLUSTER SETSLOT 11677 NODE <des_node_id>
如下图:
(2)查看状态
【8.3】slot 迁移指定 slot(基于特定值,不数据)
基本流程:
(1)登录 source_node: cluster setslot move_slot migrating desc_node_id
(2)登录 desc_node: cluster setslot move_slot importing source_node_id
(3)登录 source_node: 循环执行 cluster getkeysinslot 命令,获取count个属于槽slot的键。
(4)登录 source_node: 实际迁移Key : MIGRATE host port key| destination-db timeout [COPY] [REPLACE] [AUTH password] [AUTH2 username password] [KEYS key]
(5)登录 source_node: 循环反复 (3)(4) 直到(3)中所有 key 都过去了
(6)登录 desc_node: cluster setslot 3168 node desc_node_ip
MIGRATE 使用案例
MIGRATE host port key| destination-db timeout [COPY] [REPLACE] [AUTH password] [AUTH2 username password] [KEYS key]
migrate 192.168.191.211 6383 "f" 0 30 copy auth 123456 #单个key,有密码
migrate 192.168.164.102 6379 "" 0 1000 keys string hash list set zset #多Key匹配,没密码使用
migrate 192.168.164.102 6379 "" 0 1000 copy auth password keys string hash list set zset #多Key匹配,有密码使用
案例演示(slot 中 Key 数量少):迁移 3168 slot
(1)登录 source_node: cluster setslot 3168 migrating desc_node_id
(2)登录 desc_node: cluster setslot 3168 importing source_node_id
(3)登录 source_node: cluster getkeysinslot 3168 =》得到只有一个 key f
(4)登录 source_node: migrate 192.168.191.211 6383 "f" 0 30 copy auth 123456
(5)登录 desc_node: cluster setslot 3168 node desc_node_ip
(6)登录 source_node: cluster setslot 3168 node desc_node_ip
案例演示(slot 中 key 数量极多):这个得用 shell 了啊
【8.4】迁移slot过程中终究是否可以 get/set/del key?
当前 6384/6385/6386 是主库,主从关系如下:
6384=》6381 , 6385=》6382 , 6386=》6383
192.168.191.211:6384> cluster countkeysinslot 5461
(integer) 41578
(1)迁移这个有4W多个key的 slot 5461 ,从 6384 迁移到 6385
最终发现是可以的
(2)被迁移的bigkey是否可以.操作?
192.168.191.70:6385> hget bigkey 1
-> Redirected to slot [7676] located at 192.168.191.70:6386
没测出来
【9】故障处理
【9.1】 [WARNING] The following slots are open: 5461.
Calling MIGRATE: ERR Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY)
测试情况:
迁移一个key,中途中断
报错信息:
[ERR] Calling MIGRATE: ERR Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY) redis-cli --cluster check <node-ip:port> [WARNING] Node 192.168.191.82:6387 has slots in importing state 5461. [WARNING] Node 192.168.191.211:6383 has slots in migrating state 5461. [WARNING] The following slots are open: 5461.
解决办法:
登录这两个实例,都执行 cluster setslot 5461 stable
案例:
操作前:
操作:
redis-cli -c -h 192.168.191.82 -p 6387 -a 123456 cluster setslot 5461 stable
redis-cli -c -h 192.168.191.211 -p 6383 -a 123456 cluster setslot 5461 stable
操作后:
【9.2】[ERR] Nodes don't agree about configuration!
这种错误有较多种情况。常规情况如下:
(1)集群节点的状态不一致,失去连接等等.... 通过登录节点执行 cluster nodes 查看,把node meet 回来 或该 forget 干掉就干掉
(2)集群节点配置文件参数不一致,可能是手动改 也可能是配置文件真不一致造成,把节点参数修改成一致即可
【9.3】[ERR] Not all 16384 slots are covered by nodes.
这个也有好几种情况:
(1)两个同时报错
问题:
[ERR] Nodes don't agree about configuration! >>> Check for open slots... >>> Check slots coverage... [ERR] Not all 16384 slots are covered by nodes.
解决:
redis-cli --cluster fix cluster_anyNode_ip:port
(2)正在迁移数据引起的问题
问题:
[OK] All nodes agree about slots configuration. [WARNING] Node 192.168.191.70:6386 has slots in migrating state 3168. [WARNING] Node 192.168.191.70:6381 has slots in importing state 3168. [WARNING] The following slots are open: 3168. >>> Check slots coverage... [ERR] Not all 16384 slots are covered by nodes.
解决:
如果该 slot 中有 key,参考 【8.1.3】
如果该 slot 中没有 key,
1、 cluster setslot 3168 node desc_node_id 迁移到目标节点
2、 cluster setslot 3168 stable 停止
【附录】
(1)redis-cli --cluster help
该部分转自:https://www.cnblogs.com/zhoujinyi/p/11606935.html
redis-cli --cluster help
Cluster Manager Commands:
create host1:port1 ... hostN:portN #创建集群
--cluster-replicas <arg> #从节点个数
check host:port #检查集群
--cluster-search-multiple-owners #检查是否有槽同时被分配给了多个节点
info host:port #查看集群状态
fix host:port #修复集群
--cluster-search-multiple-owners #修复槽的重复分配问题
--cluster-fix-with-unreachable-masters # 修复无法访问的主节点,6.x 可用
reshard host:port #指定集群的任意一节点进行迁移slot,重新分slots
--cluster-from <arg> #需要从哪些源节点上迁移slot,可从多个源节点完成迁移,以逗号隔开,传递的是节点的node id,还可以直接传递--from all,这样源节点就是集群的所有节点,不传递该参数的话,则会在迁移过程中提示用户输入
--cluster-to <arg> #slot需要迁移的目的节点的node id,目的节点只能填写一个,不传递该参数的话,则会在迁移过程中提示用户输入
--cluster-slots <arg> #需要迁移的slot数量,不传递该参数的话,则会在迁移过程中提示用户输入。
--cluster-yes #指定迁移时的确认输入
--cluster-timeout <arg> #设置migrate命令的超时时间
--cluster-pipeline <arg> #定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10
--cluster-replace #是否直接replace到目标节点
rebalance host:port #指定集群的任意一节点进行平衡集群节点slot数量
--cluster-weight <node1=w1...nodeN=wN> #指定集群节点的权重
--cluster-use-empty-masters #设置可以让没有分配slot的主节点参与,默认不允许
--cluster-timeout <arg> #设置migrate命令的超时时间
--cluster-simulate #模拟rebalance操作,不会真正执行迁移操作
--cluster-pipeline <arg> #定义cluster getkeysinslot命令一次取出的key数量,默认值为10
--cluster-threshold <arg> #迁移的slot阈值超过threshold,执行rebalance操作
--cluster-replace #是否直接replace到目标节点
add-node new_host:new_port existing_host:existing_port #添加节点,把新节点加入到指定的集群,默认添加主节点
--cluster-slave #新节点作为从节点,默认随机一个主节点
--cluster-master-id <arg> #给新节点指定主节点
del-node host:port node_id #删除给定的一个节点,成功后关闭该节点服务
call host:port command arg arg .. arg #在集群的所有节点执行相关命令
--cluster-only-masters #只在集群主节点执行,6.x可用
--cluster-only-replicas #只在复制节点执行,6.x可用
set-timeout host:port milliseconds #设置cluster-node-timeout
import host:port #将外部redis数据导入集群
--cluster-from <arg> #将指定实例的数据导入到集群
--cluster-copy #migrate时指定copy
--cluster-replace #migrate时指定replace
backup host:port backup_directory #备份rdb到指定目录,6.x 可用
help
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.