Redis 分布式集群,分配Slots

本文记录了一次Redis集群出现故障导致网站无法正常访问的问题,并详细分析了故障原因及解决过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某天在开启了Redis集群之后,发现网站没法正常访问了,发现Nginx-lua 中的 Redis 丢失连接 …

集群下线

问题表现

通过查看 openrestry log 发现 lua脚本报错 :

2018/06/12 17:48:20 [error] 23272#0: *75665 lua entry thread aborted: runtime error: /usr/local/openresty/nginx/lua/access_by_redis.lua:67: attempt to compare boolean with number
stack traceback:
coroutine 0:
        /usr/local/openresty/nginx/lua/access_by_redis.lua: in function </usr/local/openresty/nginx/lua/access_by_redis.lua:1>, client: 66.249.65.116, server: www.leon0204.com, request: "GET /wechat-858.html HTTP/1.1", host: "www.leon0204.com"

从而 Nginx 返回 500,测试 Redis set 发现是集群处于下线状态导致的 :
这里写图片描述

原因分析

那么,这次 redis 集群宕机的原因是什么呢?

  1. 开启集群
    假设A服务器上有 127.0.0.1:6379127.0.0.1:6370 两个 Redis 节点。在 节点 6379 的 redis.conf中开启 cluster-enabled yes ,那么节点 6379 就处于一个只包含自己的集群中。

  2. 构建集群
    127.0.0.1:6379 发送命令:
    CLUSTER MEET 127.0.0.1:6370
    就把 6370 节点 拉到了 6379 所在的集群中。

  3. 槽指派
    Redis集群通过分片的方式来保存数据库的所有键值对:整个数据库被分成16384 个 Slot ,数据库键空间的所有键被分配到这 16384 个槽中的一个,每个node 处理 0~16384 个槽。当16384个槽有任意1个没有被处理,集群处于 fail 下线状态,否则处于上线 状态。

猜想是有一些槽没有被分配处理,进行分配槽

分配槽

查看集群状态:

127.0.0.1:6379> CLUSTER INFO
cluster_state:fail
cluster_slots_assigned:7
cluster_slots_ok:7
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

可以看到集群是下线状态,有 7 个 Slot 已经被分配,由于有 slots没有分配干净,所以集群处于 fail 下线状态,下面进行分配 slots

root@iZm5eabkgmsfy2phj5pr1xZ:~# redis-cli -h 127.0.0.1  -p 6379 -a 密码 cluster addslots {0..5000}
(error) ERR Slot `0` is already busy
root@iZm5eabkgmsfy2phj5pr1xZ:~# redis-cli -h 127.0.0.1  -p 6379 -a 密码 cluster addslots 5
OK
...
...
root@iZm5eabkgmsfy2phj5pr1xZ:~# redis-cli -h 127.0.0.1  -p 6379 -a 密码 cluster addslots {8400..12000}
(error) ERR Slot  `11955` is already busy
root@iZm5eabkgmsfy2phj5pr1xZ:~# redis-cli -h 127.0.0.1  -p 6379 -a 密码 cluster addslots {8400..11954}
OK
root@iZm5eabkgmsfy2phj5pr1xZ:~# redis-cli -h 127.0.0.1  -p 6379 -a 密码 cluster addslots {13001..16383}
OK

先来看看分配完成集群的状态,和slot_assigned的数目:

127.0.0.1:6379> CLUSTER NODES
151ce5ca0524b02c7af07402dcb40f5d678f7bb1 :6379 myself,master - 0 0 0 connected 0-16383
127.0.0.1:6379> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:1
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

# 可以正确的 set 了
127.0.0.1:6379> set leon leon0204
OK
127.0.0.1:6379>

可以看到此时 slots 已经分配了 16384 个,本机 作为master 集群上线。也可以正常的使用。

slots 分配过程中遇到的断点

可以看到这里不断有一些slots : 1151 1389 1909 5798 6918 8399 11955 显示已经被分配了,这是为什么呢,是不是我把 6379 加入集群之后,已经默认给我分配了这些 槽?所以再我再次分配时,冲突了?

刚刚我分配 0,16383 个槽给 当前node节点时,提示槽X已经busy 的 有

1151 1389 1909 5798 6918 8399 11955

我们知道,当集群被建立之后,集群的整个数据库就会被分配到 16383 个槽中,类似于分片的概念 。那么验证下这些 key 的 slots 节点,就可以验证上面的冲突。

#所有key
127.0.0.1:6379> KEYS *
1) "pyq"
2) "user:183.234.61.216:freq"
3) "leon0204"
4) "name"
5) "funet"
6) "goodsId"
7) "test"

我们查看 这些key 被分配的槽号


127.0.0.1:6379> CLUSTER KEYSLOT "pyq"
(integer) 1151
127.0.0.1:6379> CLUSTER KEYSLOT "user:183.234.61.216:freq"
(integer) 1909
127.0.0.1:6379> CLUSTER KEYSLOT "leon0204"
(integer) 11955
127.0.0.1:6379> CLUSTER KEYSLOT "name"
(integer) 5798
127.0.0.1:6379> CLUSTER KEYSLOT "funet"
(integer) 8399
127.0.0.1:6379> CLUSTER KEYSLOT "goodsId"
(integer) 1389
127.0.0.1:6379> CLUSTER KEYSLOT "test"
(integer) 6918
总结

正好和上面的 addslots 过程中,冲突的 slots 吻合 ,7个key 对应7 个 随机散落的 slot,造成了分配过程中遇到的冲突。

slots没有分配完成,造成了集群的failed ,问题解决。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值