本文主要介绍分布式数据存储的核心算法,也就是数据分布的算法,主要包含:hash
算法 、一致性hash
算法(memcached) 以及redis cluster中使用的hash slot
算法。
- 数据分布其实就是数据如何分布到多个不同的节点上。
hash算法
hash算法的话,主要是对一个key计算hash值,然后再对节点数量取模,映射到某个节点上。
缺点
假设Redis中使用了这种古老的hash算法,就会导致某个节点宕机后,key重新取模,分布在不同的节点上了。
或者举个例子,本来想查找 key为helloworld的数据,之前通过set值操作分布在node3上,然后现在node2宕机了,helloworld的hash值对2取模了,算出来就不再node3上,就导致node3上helloworld对应的数据就无效了,反正我现在基于最新的node数量来取模的,之前的数据都不作数了。
这就是大大的坑爹了,此时如果没有重新写入数据的操作,那么直接就崩了,我去get数据是从和之前不同的节点上获取的,肯定是没有数据的;那么就会去数据库中查找,数据库在高并发场景下的压力太大了,会扛不住的。
如果Redis 使用了该算法,就会导致,只要任意一个节点宕机了,大量的缓存数据就会失效,大量的请求无法获取有效的缓存数据,就会将压力全部移交给数据库,而数据库根本扛不住高并发。
所以这种算法是千万不要用的。
一致性hash算法
一致性hash在古老的hash算法基础上作了改进。
- 一致性hash的底层结构是一个环,环上有2的32次方个点,即0、1、2、4、8 、...、 2^32-1
- 环上的每一个点都有一个hash值
- 圆环上放着不同的节点机器。
一致性hash的步骤:
- 计算key的hash值
- 用上一步的值 % (2^32),用于确保key能映射到环上的某一个点(避免映射到环外),即某个key在环上对应的点是:hash(服务器的IP地址) % 2^32
- key落到圆环上以后,就会按照顺时针寻找距离自己最近的一个节点。
假如一台节点机器宕机了,那么原本在那台机器上的数据会受到影响,按照顺时针的方式,之前的节点机器宕机了,就会走到下一台机器上去,而下一台机器上是没有数据的,导致部分流量瞬间涌入数据库,重新建立缓存数据。
图画的比较丑,请见谅!
概括
一致哈希将每个对象映射到圆环边上的一个点,系统再将可用的节点机器映射到圆环的不同位置。查找某个对象对应的机器时,需要用一致哈希算法计算得到对象对应圆环边上位置,沿着圆环边上查找直到遇到某个节点机器,这台机器即为对象应该保存的位置。 当删除一台节点机器时,这台机器上保存的所有对象都要移动到下一台机器。添加一台机器到圆环边上某个点时,这个点的下一台机器需要将这个节点前对应的对象移动到新机器上。
一致性哈希的改进
思考一个问题,我们的一致性哈希算法是按照顺时针的方式来实现数据分布的,如果某个区间的哈希值比较多,就会导致大量的数据涌入一个节点,就会导致节点的热点问题,从而出现性能瓶颈。
为了解决这个问题,一致性哈希算法采用了“虚拟节点”。
即在环上均匀生成多个 虚拟节点,后续 请求先找虚拟节点,然后再通过虚拟节点找到对应的真实节点。
因此,只要保证虚拟节点是均匀分布的,就可以实现数据均匀分布在不同的节点上。
hash slot算法
再来看一下redis cluster的hash slot算法。
redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot。
redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot
hash slot使得node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去(移动hash slot的成本是非常低的)
参考内容
- https://mp.weixin.qq.com/s/FZgMPcs7VolP_04fworiRA
- https://zh.wikipedia.org/wiki/%E4%B8%80%E8%87%B4%E5%93%88%E5%B8%8C
- 《中华石杉亿级流量》
本文使用 mdnice 排版