Redis Cluster(分片机制)
分片集群(cluster):解决海量存储和高并发写的问题
特点:
-
集群中有多个master,每个master保存不同数据,
-
每个master都可以有多个slave节点,保证高并发读
-
无须哨兵机制,master之间互相通过ping检测彼此健康状态
-
客户端请求可以访问任意节点,最终都会被转发到正确节点
问题:集群中master宕机会发生什么?
该实例与其他实例失去链接;发现疑似宕机;确定下线,提升slave为新的master
问题:如何找到正确节点?
通过散列插槽。redis会把每个master节点映射到0-16383共16384个插槽(hash slot)上。例如:redis1(slots:0-5460),redis2(slots:5461-10922),redis3(slots:10923-16383)。数据key不是与节点绑定而是与插槽绑定,redis会根据key的有效部分(有“{}”看“{}”里的,无就看整体)利用CRC16算法计算hash值,然后对16384取余确定slot值。
问题:如何保证同一类数据保存在同一实例?
利用“{}”,“{}”中的有效值一致,则会保存在同一插槽所对应的redis节点上
问题:如何进行集群伸缩?
addnode增加节点和reshared分配插槽,手动将集群中的某一节点的插槽分配给新加入的节点,分配时原节点会将插槽上的数据转移给新节点。
问题:为什么要设计插槽机制?
- 基于一致性哈希算法的角度,在容错和扩展问题上,对受影响的数据进行了转移。哈希槽的设置本质上是通过对槽位的转移
- 把故障节点负责的槽位转移到其他正常的节点上。扩展节点也是一样,把其他节点上的槽位转移到新的节点上。
- 哈希槽也解决了数据分配的问题,redis cluster的槽位空间可以通过手动分配。机器硬盘小可以分配少一点槽位,机器硬盘大可以分配多一点槽位。
- 和普通哈希的区别:一个是对机器数取余,是会变的;一个是对固定的16384取余,是不变的,变的是槽位分布。
- 和一致性哈希的区别:插槽机制对于各个机器的槽位分布可控。
问题:一致性哈希算法解决了什么问题?自身又有什么问题?
- 考虑一种情况:假设有三台机器,通过简单hash并取余来确定数据在哪台机器上(keyA的哈希值为4,所以落在4%3=1第二台机器上),当数据量不断扩大需要增加机器时,原本应落在第二台机器的A数据,落在了4%4=0的第一台机器上,此时其根本没有A数据的值。因此集群水平扩展的时候,会引起缓存击穿(热点key失效)、缓存穿透(数据库中就不存在)、雪崩(大量热点失效),并且影响的数据和影响的机器也是大量且不固定的(基于取余),扩展和容错都很糟糕,因此提出了一致性哈希算法。
- 一致性哈希考虑哈希空间为一个圆环。对于各个key,其真正的存储位置是按顺时针找到的最近的第一个存储节点。例如keyA顺时针找到的最近的节点是NodeA,因此NodeA负责keyA,同理NodeB负责KeyB,NodeC负责keyC。当NodeB宕机时,KeyB此时最近的节点则变为NodeC。即当NodeB宕机时,受影响的只是NodeA到NodeB之间本应NodeB存储的数据,且只有
NodeC此时压力增大,集群内其他节点不会受到影响。 - 同时,当需要增加新节点NodeX在NodeB和NodeC之间时,受影响的也只是NodeB到NodeX之间的数据,受影响的机器
也只有NodeX本身。 - 可见,一致性哈希很好地解决了集群容错和扩展的问题。
- 但是当集群中节点太少并且分布不均匀(根据ip分布),就会导致部分节点数据太多(节点间距离大),部分节点数据太少
的问题,也就是说无法控制节点自身存储数据的分配。
问题:为什么使用16384?
crc16算法最大能得到2^16-1=65535。尽管crc16能得到65535个值,但redis选择16384个slot,是因为16384的消息只占用了2k,而65535则需要8k。正常的心跳包携带节点的完整配置,65535太大了。