数据分布算法
传统hash
- hash:
- 最简单的数据分布算法,对进来的key进行hash,然后对节点数据进行取模,就知道分布到哪个节点上了;
- 缺点就是: 如果一个节点宕机,所有缓存的位置都要发生改变,当服务器数量发生改变时,所有缓存在一定时间内是失效的,会引起缓存的雪崩,可能会引起整体系统压力过大而崩溃(大量缓存同一时间失效)
一致性hash
-
实际上就是引入了一个圆环的概念, 让每个数据的hash分布到整个圆环,然后顺时针去找离他最近的节点存储;
- hash算法的取模法是对服务器的数量进行取模,而一致性哈希算法是对2^32取模,
- dubbo的复杂均衡有用到该算法;
-
好处:
- 使用hash算法,服务器数量发生改变时,所有服务器的所有缓存在同一时间失效了;
- 而使用一致性哈希算法时,服务器的数量如果发生改变,并不是所有缓存都会失效,而是只有部分缓存会失效,前端的缓存仍然能分担整个系统的压力,而不至于所有压力都在同一时间集中到后端服务器上;
-
hash环偏斜:
- 1号、2号、3号、4号、6号数据均被缓存在了服务器A上;只有5号被缓存在了服务器B上;服务器C上甚至没有缓存任何图片
- 如果出现上图中的情况,A、B、C三台服务器并没有被合理的平均的充分利用,缓存分布的极度不均匀,而且,如果此时服务器A出现故障,那么失效缓存的数量也将达到最大值,在极端情况下,仍然有可能引起系统的崩溃;
- 上图中的情况则被称之为hash环的偏斜 ;
- 我们应该怎样防止hash环的偏斜?虚拟节点
-
增加虚拟节点:
- 为了解决这个数据负载均衡的问题,搞出来虚拟节点; 把真实节点搞一堆虚拟节点分布到环,那么整个区间的数据会落到这些虚拟节点上;
- 虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大。
哈希槽hash slot
-
Redis 集群并没有直接使用一致性哈希算法,而是使用了哈希槽 (slot) 的概念;Redis 没有直接使用哈希算法 hash(),而是使用了crc16校验算法。槽位其实就是一个个的空间的单位。
-
相比与上面的一致性哈希数据分布算法不同:
- hash slot是使用了 **crc16校验 **算法;
- 是直接对 **16384 **进行取模;而不是对机器数(2^32)进行取模;
为什么哈希槽的大小是固定的16384?
-
节点间的通信性能方面:
-
首先我们知道redis节点存的是槽,槽里面再存数据;
-
当我们集群部署时,槽分配到每一个主节点上;负责各自读写,但是每个节点之间是需要进行一个通信的,也就是不断地pingpong机制,让每个节点连接对方的信息;
-
所以就涉及到传输的问题,既不能太大,导致占用带宽,也要保证数据都要传过去;
-
消息头里面有个myslots的char数组,长度为16383/8,这其实是一个bitmap,每一个位代表一个槽,如果该位为1,表示这个槽是属于这个节点的。
-
如果槽位过大,65536那么发送心跳信息的消息头就会变大8K,发送的心跳包过于庞大;
-
所以选用16384刚刚好;
-
-
redis的集群主节点数量基本不可能超过1000个
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。
-
槽位越小,节点少的情况下,压缩率高
Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
而16384÷8÷1024=2kb,怎么样,神奇不!
压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
而16384÷8÷1024=2kb,怎么样,神奇不!
综上所述,作者决定取16384个槽,不多不少,刚刚好!