Redis hash槽分配

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis hash槽分配相关的知识,希望对你有一定的参考价值。

参考技术A Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value
时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。使用哈希槽的好处就在于可以方便的添加或移除节点。当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。

"用了哈希槽的概念,而没有用一致性哈希算法,不都是哈希么?这样做的原因是为什么呢?
"Redis Cluster是自己做的crc16的简单hash算法,没有用一致性hash。Redis的作者认为它的crc16(key) mod 16384的效果已经不错了,虽然没有一致性hash灵活,但实现很简单,节点增删时处理起来也很方便。"为了动态增删节点的时候,不至于丢失数据么?"节点增删时不丢失数据和hash算法没什么关系,不丢失数据要求的是一份数据有多个副本。“还有集群总共有2的14次方,16384个哈希槽,那么每一个哈希槽中存的key 和 value是什么?”当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,每个分区里有很多key。

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槽分配的主要内容,如果未能解决你的问题,请参考以下文章

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

redis 集群新增节点,slots槽分配,删除节点, [ERR] Calling MIGRATE ERR Syntax error, try CLIENT (LIST | KILL | GET...

redis集群

Redis集群重新分片(新增/移除节点)理论

redis之cluster(集群)

硬核干货!Redis 分布式集群部署实战