文章目录
redis集群是一个提供在多个Redis节点间共享数据的程序集,支持多个master。这是由于哨兵加主从复制的方式具有缺陷,由于数据量过大的情况下,单个master的复制集难以承担,因此需要多个复制集进行集群,其作用主要是提供给在多个Redis节点间共享数据的程序集。
一、集群的功能
- Redis集群支持多个Master,每个Master由可以挂载多个Slave。因此,它也具有读写分离、支持数据高可用和支持海量数据的读写存储操作的特点。
- 无需使用哨兵功能,集群自带了sentinel的故障转移机制,内置高可用的支持。
- 客户端与集群的连接只需要与集群中的任一可用节点连接即可。
- 槽位
slot
负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系。
二、Redis集群的槽位slot和分片
2.1、概念
Redis分成了16384个哈希槽,每个哈希槽都可以存放一个key-value
键值对,即设置了16384个主节点的集群上限(但建议大小为1000),每个key
通过CRC16校验后对16384取模来决定放置在哪个槽,
使用Redis集群时将存储的数据分散到多台redis机器上,这就称为分片。
计算当前数据应该放在哪个槽位上的公式为:
H
A
S
H
_
S
L
O
T
=
C
R
C
16
(
k
e
y
)
m
o
d
16384
HASH\_SLOT=CRC16(key) mod 16384
HASH_SLOT=CRC16(key)mod16384
使用槽位和分片的优势
这种结构的最大优势是方便扩缩容和数据分派查找。无论添加删除或者改变某个节点都不会造成集群不可用的情况。
2.2、slot槽位映射的算法
2.2.1 哈希取余分区
预先确定好机器台数,通过
h
a
s
h
(
k
e
y
)
%
N
台机器
hash(key)\%N台机器
hash(key)%N台机器,计算哈希值,来决定数据key-value
映射到哪一台机器上。
优点
简单且有效。使得每一台机器固定处理一部分请求,起到负载均衡+分而治之的作用。
缺点
扩缩容比较麻烦,再台数数量变化的情况下,会导致hash取余变化从而使得数据重新洗牌。
2.2.2 一致性hash算法
一致性hash算法是为了解决分布式缓存数据变动和映射的问题。当服务器数量发生变化的时候,尽量减少影响客户端到服务器的映射关系。
算法步骤
1、构建一致性圆环:构建全量集合,即对2^32
取模。
2、Redis服务器IP节点映射:将服务器IP节点映射到环上。
3、将key
值映射到环上:将key
值映射到环上,并且从该key
值的位置沿着顺时钟方向走,遇到的第一台服务器就是定位到的服务器。
![Panda](https://i-blog.csdnimg.cn/blog_migrate/6fcebe8817e077ad6828c6ba956ef303.png)
优点
1、容错性,如果上图之中的服务器节点C宕机了,那么只会影响节点B和节点C之间的key
,并且这些key
也只是转移到了服务器节点D上,不会影响整个数据。
2、扩展性,如果要添加一个新服务器节点E,那么也只会影响一个区间内的数据,而不会使得整个数据发生转移。
缺点
Hash环的数据倾斜问题,一致性Hash容易在服务节点太少,数据太多时发生数据倾斜问题。导致数据大部分集中在一台机器上,从而使得服务器节点发生变化时,发生大规模的数据迁移。如下:
![Panda](https://i-blog.csdnimg.cn/blog_migrate/ec3f244132edc8d27494699ae7fde263.png)
2.2.3 哈希槽分区
哈希槽实质是一个由[0, 2^14-1]
数组形成的hash slot
空间。由于一致性哈希算法存在数据倾斜问题,所以提出了哈希槽分区算法
。哈希解决了映射问题,通过使用key
的哈希值来计算所在的槽,便于数据分配。槽解决了粒度问题,便于数据移动。
哈希槽计算
H
A
S
H
_
S
L
O
T
=
C
R
C
16
(
k
e
y
)
m
o
d
16384
HASH\_SLOT=CRC16(key) mod 16384
HASH_SLOT=CRC16(key)mod16384
面试题:为什么redis集群的最大槽数是16384?
CRC16产生的hash值由16bit,即可以产生2^16=65536
个值,但我们只用16384个槽就行了,原因如下:
1、槽位越少,节点少的情况下,压缩比高,容易传输
Redis主节点的配置信息中显示它所负责的哈希槽是通过bitmap来保存的。在传输的过程中会对bitmap进行压缩,如果节点很少但是哈希槽很多的话,bitmap的压缩率就很低。
2、redis的集群主节点数量基本不可能超过1000个
如果节点超多1000个,会导致心跳包消息体内携带的数据过大而引发网络拥堵。对于节点数在1000以内的redis集群,16384个槽位够用了。
3、如果设置槽位为65536,发送心跳包的消息头达8Kb,发送的心跳包过于庞大。
消息头中最占空间的是myslot[CLUSTER_SLOTS/8]
,当槽位为65536是,这部分大小为65538 / 8 / 1024 = 8kb
,当槽位为16384时,这部分大小为16384 / 8 / 1024 = 2kb
。每秒钟redis节点都要发送一定数量的心跳包,所以如果设置的太大,浪费带宽。
面试题:redis集群会不会写丢失?
redis集群不保证强一致性,在特定情况下,会丢掉一些系统收到的写入请求命令。