Hash分区

  1 hash分区规则

   由于Redis Cluster(集群)采用哈希分区规则,所以先介绍下常见的哈希分区规则。常见的哈希规则:节点取余分区规则、一致性哈希分区(Consistent hashing)、虚拟槽(Virtual slot)分区。

  2 节点取余分区

   使用特定的数据,如Redis的键或用户ID,再根据节点(运行在集群模式下的Redis服务器)的数量N使用公式:hash(key) % N计算出hash值,用来决定数据存储在哪个节点上。例如,将20个数据存储在4个节点上:

4个节点存储20个数据

   如果此时增加一个节点,那么经过重新hash计算后得到的分布如下(其中数据1、2、3、20这4个数据存储的位置没有改变,其他的数据位置都发生了改变。):
5个节点存储20个数据

  节点取余分区缺点:在节点的数量变化时,如扩容或收缩节点时,数据节点映射关系需要重新计算,会导致大量数据重新迁移。
   节点取余分区优点:实现简单。常用于数据库分库分表规则,通常先预先根据数据数量规划好区数,保证可以支撑一段时间,再根据负载情况将数据迁移到其他数据库中,扩容时通常采用翻倍扩容,这样大约只需迁移一半的数据量,从而避免映射全部被打乱导致全量迁移的情况。

  2 一致性哈希分区

  一致性哈希分区实现思路是为系统中的每个节点分配一个token,范围是0~232-1,这些token构成一个哈希环。数据读写执行节点查找操作时,先根据key计算出哈希值,然后顺时针找到第一个遇到的token节点。

一致性哈希数据分布

  这种方式相对于节点取余的好处在于加入和删除节点只影响哈希环中相邻的节点,对其他节点无影响。
  如下图表示新增一个节点,经过hash计算出其位置为在节点2和节点3之间,它对数据分布影响的范围只是节点3和节点4之间的绿色部分的数据无法命中,对其他的节点的无影响。
新增一个节点的数据分布

  考虑这样的一种情况,如果只有3个节点,且节点在哈希环上的分布是可能是这个样子的,即使数据分布的均匀,大量的数据存储在节点0上,而节点1、2不会存储多少数据,节点0的负载会很高,这种情况就是哈希倾斜性导致的。

哈希倾斜导致的数据分布

  一致性哈希分区的缺点:

(1) 当使用少量节点时,节点变化将大范围的影响哈希环中的数据映射,因此这种方法不适合少量数据节点的分布式方案。
(2) 加减节点会造成哈希环中的部分数据无法命中,需要手动处理这部分数据。
(3) 由于哈希倾斜性,当数据节点较少时,往往导致某个节点负载过大而其他节点负载过小,负载不均衡。

  3 虚拟槽分区

  Redis Cluster采用的就是虚拟槽分区。虚拟槽分区巧妙的使用了哈希空间,使用分散度良好的哈希函数将所有的数据映射到一个固定范围的整数集合中,整数定义为槽(slot)。这个范围一般远远大于节点数,这是为了消除哈希的倾斜性,便于数据拆分和扩展。例如Redis Cluster槽的范围是0~16383。槽是集群内数据管理和迁移的基本单位,每个节点都会负责一定数量的槽。
  如在Redis中,假设有5个节点,每个节点平均负责3276个槽。

槽集合和节点的关系

  由于采用了分散性较好的哈希函数,所有的数据大致均匀分布在0~16383各个槽中,计算公式为slot = CRC16(key) & 16383,当要操作数据时,只需要计算出相应的槽,并根据槽即可找到对应的节点。
键的映射过程

  虚拟槽分布的特点:

(1) 解耦数据和节点之间的关系,简化了节点的扩容和收缩。
(2) 解决了普通一致性哈希分区只有少量节点负载不均衡问题。
(3) 支持节点、槽、键之间的映射查询,用于数据路由。

  4 小结

  (1) 常见的哈希分区规则有:节点取余分区、一致性哈希分区和虚拟槽分区。
  (2) Redis Cluster数据分区规则采用虚拟槽方式,所有的键映射到16384个槽中,每个节点负责一部分槽和相关数据,实现数据和请求的负载均衡。
  本文完


  注:本文参考《Redis开发与运维》,如发现错误,请指正!

你可能感兴趣的:(Hash分区)