Redis集群Hash槽分配异常 CLUSTERDOWN Hash slot not served的解决方式

Posted 祂一直在

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis集群Hash槽分配异常 CLUSTERDOWN Hash slot not served的解决方式相关的知识,希望对你有一定的参考价值。

在搭建Redis5.x版本的集群环境出现各节点无法互相发现与Hash槽分配异常 CLUSTERDOWN Hash slot not served的情况

在Linux同一台服务器下搭建伪集群——

127.0.0.1:6380
127.0.0.1:6381
127.0.0.1:6382
127.0.0.1:6383
127.0.0.1:6384
127.0.0.1:6385

启动Redis集群,然后连接其中一台客户端,随便set一个指令,测试集群是否可行,结果报出异常(error)CLUSTERDOWN Hash slot not served提示——

[root@localhost bin]# redis-cli -c -p 6380
127.0.0.1:6380> auth longshine
OK
127.0.0.1:6380> set a 1
(error) CLUSTERDOWN Hash slot not served

首先,先看一下集群各个节点是否能互相发现,执行以下指令查看各个节点连接情况—— cluster nodes

127.0.0.1:6380> cluster nodes
e59d13b92dca3edd52d2928083f85aff5a87cb84 :6380@16380 myself,master - 0 0 0 connected

接着再检查一下当前集群状态,发现目前状态为fail,说明集群没有互连成功—cluster info

127.0.0.1:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

发现,Redis搭建的集群没有互相发现,故而,只需要在其中一台客户端上执行以下指令,手动帮助该节点去发现其他两个节点,因集群是互连的,所以只需要在其中一台上手动发现另外两台即可— cluster meet

127.0.0.1:6380> cluster meet 127.0.0.1 6387
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6381
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6382
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6383
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6384
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6385
OK

完成以上指令,查看各个节点状态,发现当前节点已经能发现其他几台机器节点了— cluster nodes

127.0.0.1:6380> cluster nodes
b5736409d6e318fe53942b8cfd3a47c9dd8406e3 127.0.0.1:6383@16383 master - 0 1669613645000 3 connected
19e38f8eaca8be3d8e955ec95632c36e9f9a748d 127.0.0.1:6381@16381 master - 0 1669613646000 1 connected
e59d13b92dca3edd52d2928083f85aff5a87cb84 127.0.0.1:6380@16380 myself,master - 0 1669613644000 0 connected
b3e67205d783eaef13c3968150367100bdab4d07 127.0.0.1:6385@16385 master - 0 1669613646000 5 connected
23bcc3819d06c6853949a59d33ddaf922fb86fef 127.0.0.1:6384@16384 master - 0 1669613647596 4 connected
054b0b5ff6f383c34c33ba98a5ac2fb9658f08e4 127.0.0.1:6382@16382 master - 0 1669613646593 2 connected

再测试集群状态,发现状态依然还是失败,且还报CLUSTERDOWN Hash slot not served

127.0.0.1:6380> set key1 ll
(error) CLUSTERDOWN Hash slot not served
127.0.0.1:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_ping_sent:1211
cluster_stats_messages_pong_sent:53
cluster_stats_messages_meet_sent:13
cluster_stats_messages_sent:1277
cluster_stats_messages_ping_received:53
cluster_stats_messages_pong_received:47
cluster_stats_messages_received:100

到这一步,说明当前集群存在hash槽异常情况,那么,可以执行以下指令修复下—— 

[root@localhost bin]# ./redis-cli --cluster fix 127.0.0.1:6380

 回车执行,顿时就会运行打印很多以下信息,说明正在对16384个hash槽重新分配——

>>> Covering slot 15195 with 127.0.0.1:6380
>>> Covering slot 4062 with 127.0.0.1:6380
>>> Covering slot 7708 with 127.0.0.1:6380
>>> Covering slot 11909 with 127.0.0.1:6380
>>> Covering slot 9828 with 127.0.0.1:6380
>>> Covering slot 5152 with 127.0.0.1:6380
>>> Covering slot 8446 with 127.0.0.1:6380
>>> Covering slot 5345 with 127.0.0.1:6380
......

等运行完成后,我们再检查一下集群状态,发现状态已经由刚刚的fail变出ok了,说明hash槽已经正确分配——

127.0.0.1:6380> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:6
cluster_current_epoch:42
cluster_my_epoch:41
cluster_stats_messages_ping_sent:1382
cluster_stats_messages_pong_sent:224
cluster_stats_messages_meet_sent:13
cluster_stats_messages_sent:1619
cluster_stats_messages_ping_received:224
cluster_stats_messages_pong_received:218
cluster_stats_messages_received:442
127.0.0.1:6380> set key1 lll
OK
127.0.0.1:6380> get key1
"lll"

这样就解决了。

redis 数据分区--一致性hash&&虚拟槽分区

参考技术A 1.节点区域分区:
使用特定的数据,如redis的键或用户ID,再根据节点数量N使用公式:hash(key)%N计算出hash值,用来决定数据映射到哪一个节点上.

这种方案的问题是:
当节点数量变化时,需要重新计算hash,会导致数据的重新迁移.

2.一致性hash算法
一致性hash算法实现思路是为系统中每一个节点分配一个token,范围在0~2^32,这些token构成一个hash环.数据的读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该hash的token节点.

好处:
这种方式最大的好处就是,在加入或删除节点时,只影响hash环中相邻的两个节点,对其他节点无影响.

问题:

3.虚拟槽算法

使用分散度较好的hash函数,将所有的数据映射到 比如0~16383(2^14)范围的槽中(slot).这个槽的数量一般远远大于实例的数量.

槽是集群数据管理和迁移的基本单位.采用大范围槽的主要目的是为了方便数据拆分和集群扩展.

每一个实例会映射一部分范围的槽.

特点:
1.解耦数据和节点之间的关系,简化扩容和锁容的难度
2.节点自身维护槽的映射关系,不需要客户端或代理服务维护槽分区的元数据.
3.支持节点,槽,键之间的映射查询,用于数据路由,在线伸缩灯场景.

HashTags(面试)
Mset k1 v1 k2 v2 k3 v3
通过分片手段,可以将数据合理的划分到不同的节点上,这本来是一件好事。但是有的时候,我们希望对相关联的业务以原子性方式进行操作。举个简单的例子
我们在单节点上执行MSET (m表示多个,一次向redis设置多个key和值), 它是一个原子性的操作,我们要求所有给定的key要在同一时间内被设置,不能出现某些指定的key被更新另一些指定的key没有被更新的情况。但是在集群环境下,我们仍然可以执行MSET命令,但它的操作不在是原子操作,会存在某些指定的key被更新,而另外一些指定的key没有改变,原因是多个key可能会被分配到不同的机器上。
所以,这里就会存在一个矛盾点,及要求key尽可能的分散在不同机器,又要求某些相关联的key分配到相同机器。
这个也是在面试的时候会容易被问到的内容。怎么解决呢?
从前面的分析中我们了解到,分片其实就是一个hash的过程,对key做hash取模然后划分到不同的机器上。所以为了解决这个问题,我们需要考虑如何让相关联的key得到的hash值都相同呢?如果key全部相同是不现实的,所以怎么解决呢?在redis中引入了HashTag的概念,可以使得数据分布算法可以根据key的某一个部分进行计算,然后让相关的key落到同一个数据分片;
举个简单的例子,假如对于用户的信息进行存储,
redis:store:1001、redis:store:1002
那么通过hashtag的方式,
redis:store:1001、redis:store:1002; 表示
当一个key包含 的时候,就不对整个key做hash,而仅对 包括的字符串做hash。

以上是关于Redis集群Hash槽分配异常 CLUSTERDOWN Hash slot not served的解决方式的主要内容,如果未能解决你的问题,请参考以下文章

redis 数据分区--一致性hash&&虚拟槽分区

redis集群

Redis--集群

redis分布式集群容错扩展机制

记一次redis集群异常.(error) CLUSTERDOWN The cluster is down

Redis集群cluster实操