前言
在阅读公司自主封装的jedis源码过程中,了解到sentinel集群连接多个master,当客户端连接sentinel获取对应key的主节点信息时,用到了一致性hash算法。
而最新版本的redis集群cluster模式下,用的hash slot模式。
所以针对这两个问题,积累一下相关知识点,便于理解。
普通hash
在正常集群分布时,需要对redis的key进行负载均衡,
简单方案,:
- 1.假设现在有4台服务器
- 2.对key进行hash并取余,得到对应的数值找到对应的服务器。
存在问题:如果线上4台服务器无法满足需求时,增加一台变成5台,这时候取余的结果跟之前的数值就存在区别,导致对应的key找不到数据,而且这个可能影响大部分的key都找不到。
一致性hash
一致性 Hash 算法通过构建环状的 Hash 空间替线性 Hash 空间的方法解决了这个问题,整个 Hash 空间被构建成一个首位相接的环。
如上图,上方两个图为普通hash环,其具体的构造过程为:
- 1.先构造一个长度为 2^32 的一致性 Hash 环
- 2.计算每个缓存服务器的 Hash 值,并记录,这就是它们在 Hash 环上的位置
- 3.对于每个图片,先根据 key 的 hashcode 得到它在 Hash 环上的位置,然后在 Hash 环上顺时针查找距离这个 Key 的 Hash 值最近的缓存服务器节点,这就是该图片所要存储的缓存服务器。
这时,当服务器扩容时,少部分的缓存会命中到新的节点上,其他的并不会受影响。反之,当服务器节点被删除时,只会影响之前映射到当前节点的key,转移到顺时针方向的下一个节点。
但是以上的普通hash环会存在一个问题,当节点移除时,原有节点的数据会全量打到一个节点上,导致那个节点的数据倍增,同理,如果节点新增时,只会影响其中一个节点,其他节点的压力并不会移除。
这时,引入了包含虚拟节点的hash环,扩展整个环上的节点数量,可以将每台物理缓存服务器虚拟为一组虚拟缓存服务器,使得 Hash 环在空间上的分割更加均匀。
如图中下方图,node1x代表节点1,依次类推,通过寻找虚拟节点,然后找到对应的真实节点,只要虚拟节点足够多,节点会更均匀的分布在环上。
此时,新增一个节点,所影响的key会均匀的从其他节点转移到新的节点上,同理删除一个节点,节点上的缓存会均匀的转移到其他节点上。
一致性hash也有一些不足的地方:
- 1.节点过多,或者更新频繁,查询效率会比较低下。
- 2.需要一个服务进行负载均衡。
针对这两个问题,redis有几个方案:
- 1.集群方案,hash slot
Redis Cluster 通过分片的方式将整个缓存划分为 16384 个槽,每个缓存节点就相当于 Hash 环上的一个节点,接入集群时,所有实例都将均匀占有这些哈希槽,当需要查询一个 Key 是,首先根据 Key 的 hashcode 对 16384 取余来得到 Key 属于哪个槽,并映射到缓存实例上。
把16384个槽抽象成20个哈希槽位,如果有4个节点,分配的哈希槽为0-4,5-9,10-14,15-19,当新增一个节点时,将每个节点的哈希槽的一部分取出来到第五个节点上,取出0,5,10,15形成新的节点哈希槽。删除也同理 - 2.中心化
公司使用sentinel的形式,把sentinel当做中心来对redis进行调度 - 3.去中心化
每个节点都保存完整的哈希槽-节点的映射表。
这样的话,无论向那个节点发出寻找缓存的请求,都会转移到对应的节点上。
hash slot
待补充