一致性hash

前言

说出来大家可能不相信,我昨天做梦梦到自己在面试,然后面试官问了我这个问题哈哈~然后我就打算按照自己的理解写一写。如果有写的不对的欢迎大家指正!

直接开始

普通hash算法

什么是一致性hash?-LMLPHP

普通hash算法就是把存储的key取hash然后再对节点数取模之后判断key所在节点的位置,

如上图所示,假设现在有key1,key2,key3,key4四个key,通过上面说的方法均匀分布在了这4个节点上面。看上去非常nice~

但是如果现在我们集群需要扩容,增加一台机器会发生啥?

什么是一致性hash?-LMLPHP

可以看到,由于现在增加了一台机器,所以现在我们取模的对象由3变成了4。

导致什么现象呢?假设我们的数据现在没有迁移,那原来的key3和key4本来是分别在node0和node1上的,现在通过hash取模运算之后却是在node0和node3上,所以在数据不做迁移的情况下会导致原有的缓存会大量失效。然后这种大面积的数据迁移是非常麻烦的!

这是扩容导致的问题,如果集群中的节点宕机呢?

什么是一致性hash?-LMLPHP

现在node2挂了,集群节点数量变成了2,对应的key通过hash取模之后所在的节点也会变化。导致node2上面原有的key查询不到,会直接查库。其余的key,除了key1能正常查询外,其他key全都失效了。这时不仅涉及到数据迁移还会导致缓存穿透。

一致性hash

一致性hash其实是普通取模hash算法的改良版,其hash计算方法没有变化,但是hash空间发生了变化,由原来的线性的变成了环。缓存节点通过hash计算之后得到在hash环中的位置;key通过hash计算之后得到所在环的位置,然后顺时针方向找到第一个节点,这个节点就是存放key的节点。

什么是一致性hash?-LMLPHP

来看看一致性hash是如何解决普通取模hash中扩容和宕机的问题的。

假设现在我们增加了一个节点node3,原来的key1现在顺时针找到了新增加node3,对其余的节点没有任何影响。只需要将node0到node3之间的key迁移到新的节点即可。

什么是一致性hash?-LMLPHP

如果node2现在宕机了,那么原来的key2顺时针找到的节点会变成node0,其余节点也没有任何影响,只需要把node2上的key迁移到node0上即可。

什么是一致性hash?-LMLPHP

那这个一致性hash难道就没有啥毛病了嘛?

想一下,如果我们的节点数量很少,并且节点偏向一侧会发生什么事情?

什么是一致性hash?-LMLPHP

可以看到很大一部分的key都会落在node0上,从而导致node0的压力过大挂掉,node0挂掉之后数据同时又会向node1上转移,node1又会挂掉,最终导致整个集群不可用!这就是数据倾斜的问题,会引起节点雪崩。可想而知这个问题会很严重。

一致性hash优化

数据倾斜的问题是通过虚拟节点来解决的。

就是在节点稀疏的hash环上对物理节点虚拟出一部分虚拟节点,key会打到虚拟节点上面,而虚拟节点上的key实际也是映射到物理节点上的,这样就避免了数据倾斜导致单节点压力过大导致节点雪崩的问题。

什么是一致性hash?-LMLPHP

结语

做梦引起的一片博文。

介绍了普通取模hash的弊端,一致性hash如何解决,以及一致性hash优化的问题。

上面的介绍如果有什么不对的地方希望各位能指正~我也会虚心接受。

04-07 08:51