redis分片集群为什么采用hash槽而不采用一致性哈希

663 阅读10分钟

redis 分片集群概念

Redis分片集群将数据划分为 16384 (2^14)个槽位(哈希槽),每个Redis服务节点分配了一部分槽位,因为槽位的信息存储于每个节点中,客户端请求的key通过CRC16校验后对16384取模来决定放置哪个槽,这样也就定位到指定的节点中。

image.png

注: 每个节点都会记录哪些槽分配给了自己,哪些槽被分配给了其他节点

分片集群运维

增加节点

新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot(槽)到D上,会变成这样:

image.png

此时服务A、B、C、D通过分配各自有了对应的哈希槽,新增节点后集群会自动进行哈希槽的重新平均分配,比如上图中四个节点中每个节点的槽位数是:18384 / 4 = 4096。

当然这个你使用命令 【cluster addslots】为每个节点自定义分配槽的数量,这里有个特点,如果我们节点的机器性能有差异,那就可以为性能好的,配置更多槽位,更好的利用机器性能。

减少节点

如果减少一个节点C,redis cluster同样会自动进行槽数量的重新计算分配。整体流程就是将节点C上的slot 搬迁到节点A、B上

客户端访问节点数据

Redis cluster的主节点各自负责一部分槽,我们来看下来自客户端的请求的key是如何定位到具体的节点,然后返回对应的数据的。

image.png

来自Redis-Cli客户端的请求连接到的是集群中的任何一个节点

  1. 首先检查当前key是否存在集群中的节点。

  2. 在该节点的话就直接就直接返回key对应的结果

  3. 不在该节点的话,那么会 MOVED重定向(包含槽位和目标地址)指引客户端转向至正确的节点,并再次发送之前执行的命令

一致性哈希算法

cloud.tencent.com/developer/a…

为什么需要一致性hash算法

我们先看下如果不使用一致性hash算法,则k-v键值对是怎么样存储的

假设一开始系统中只有3个节点,则通过hash(key) % 节点个数 可以计算出 某个key 需要路由到那个redis 节点。

比如

  • key1 -> 节点1

  • key2 - > 节点2

  • key3 -> 节点3

  • key4 -> 节点1

  • key5 -> 节点2

  • key6 -> 节点3

  • key7 -> 节点1

  • key8-> 节点2

image.png 如果新增节点4,则key的路由规则将发生变化

  • key1 -> 节点1

  • key2 - > 节点2

  • key3 -> 节点3

  • key4 -> 节点4

  • key5 -> 节点1

  • key6 -> 节点2

  • key7 ->节点3

  • key8 -> 节点4

可以看到,从key4开始,所有的key的路由规则都发生了变化,因此每个节点都需要移动大量的数据。

一致性hash 如何解决这个问题

我们可以把一致哈希算法是对 2^32 进行取模运算的结果值虚拟成一个圆环,环上的刻度对应一个 0~2^32 - 1 之间。我们将节点id 进行hash 运算放入下面环中,一般我们会根据服务器的IP或者唯一别名进行哈希计算。

数据如何映射:同样key值经过哈希之后,结果映射到哈希环上,然后将结果值按顺时针方向找到离自己最近的节点上,将value存储到那个节点上。

不平衡问题:引入虚拟节点。多个虚拟节点映射一个实际节点,因为在哈希环上节点越多就分布的越均匀,即使我们现实中不会有那么多真实节点。

image.png

假设节点A被删除,那么原来落到节点A的数据需要落到节点B。因此只有B受到影响,其他节点不会受到影响。

假设在A、B之间增加节点D,那么原来落到B的部分数据将落到节点D,因此只有B受到影响,其他节点不会受到影响。

为什么Redis是使用哈希槽而不是一致性哈希呢?

  • 当发生扩容时候,Redis可配置映射表的方式让哈希槽更灵活,可更方便组织映射到新增server上面的slot数,比一致性hash的算法更灵活方便。

  • 在数据迁移时,一致性hash 需要重新计算key在新增节点的数据,然后迁移这部分数据,哈希槽则直接将一个slot对应的数据全部迁移,实现更简单。

  • 可以灵活的分配槽位,比如性能更好的节点分配更多槽位,性能相对较差的节点可以分配较少的槽位。

为什么Redis Cluster哈希槽数量是16384?

  • Redis节点间通信时,心跳包会携带节点的所有槽信息,它能以幂等方式来更新配置。如果采用 16384 个插槽,占空间 2KB (16384/8);如果采用 65536 个插槽,占空间 8KB (65536/8)。

  • Redis Cluster 不太可能扩展到超过 1000 个主节点,太多可能导致网络拥堵。

  • 16384 个插槽范围比较合适,当集群扩展到1000个节点时,也能确保每个master节点有足够的插槽

参考资料

cloud.tencent.com/developer/a…

redis 分片集群概念

Redis分片集群将数据划分为 16384 (2^14)个槽位(哈希槽),每个Redis服务节点分配了一部分槽位,因为槽位的信息存储于每个节点中,客户端请求的key通过CRC16校验后对16384取模来决定放置哪个槽,这样也就定位到指定的节点中。

注: 每个节点都会记录哪些槽分配给了自己,哪些槽被分配给了其他节点

分片集群运维

增加节点

新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot(槽)到D上,会变成这样:

此时服务A、B、C、D通过分配各自有了对应的哈希槽,新增节点后集群会自动进行哈希槽的重新平均分配,比如上图中四个节点中每个节点的槽位数是:18384 / 4 = 4096。

当然这个你使用命令 【cluster addslots】为每个节点自定义分配槽的数量,这里有个特点,如果我们节点的机器性能有差异,那就可以为性能好的,配置更多槽位,更好的利用机器性能。

减少节点

如果减少一个节点C,redis cluster同样会自动进行槽数量的重新计算分配。整体流程就是将节点C上的slot 搬迁到节点A、B上

客户端访问节点数据

Redis cluster的主节点各自负责一部分槽,我们来看下来自客户端的请求的key是如何定位到具体的节点,然后返回对应的数据的。

来自Redis-Cli客户端的请求连接到的是集群中的任何一个节点

  1. 首先检查当前key是否存在集群中的节点。

  2. 在该节点的话就直接就直接返回key对应的结果

  3. 不在该节点的话,那么会 MOVED重定向(包含槽位和目标地址)指引客户端转向至正确的节点,并再次发送之前执行的命令

一致性哈希算法

cloud.tencent.com/developer/a…

为什么需要一致性hash算法

我们先看下如果不使用一致性hash算法,则k-v键值对是怎么样存储的

假设一开始系统中只有3个节点,则通过hash(key) % 节点个数 可以计算出 某个key 需要路由到那个redis 节点。

比如

  • key1 -> 节点1

  • key2 - > 节点2

  • key3 -> 节点3

  • key4 -> 节点1

  • key5 -> 节点2

  • key6 -> 节点3

  • key7 -> 节点1

  • key8-> 节点2

如果新增节点4,则key的路由规则将发生变化

  • key1 -> 节点1

  • key2 - > 节点2

  • key3 -> 节点3

  • key4 -> 节点4

  • key5 -> 节点1

  • key6 -> 节点2

  • key7 ->节点3

  • key8 -> 节点4

可以看到,从key4开始,所有的key的路由规则都发生了变化,因此每个节点都需要移动大量的数据。

一致性hash 如何解决这个问题

我们可以把一致哈希算法是对 2^32 进行取模运算的结果值虚拟成一个圆环,环上的刻度对应一个 0~2^32 - 1 之间。我们将节点id 进行hash 运算放入下面环中,一般我们会根据服务器的IP或者唯一别名进行哈希计算。

数据如何映射:同样key值经过哈希之后,结果映射到哈希环上,然后将结果值按顺时针方向找到离自己最近的节点上,将value存储到那个节点上。

不平衡问题:引入虚拟节点。多个虚拟节点映射一个实际节点,因为在哈希环上节点越多就分布的越均匀,即使我们现实中不会有那么多真实节点。

假设节点A被删除,那么原来落到节点A的数据需要落到节点B。因此只有B受到影响,其他节点不会受到影响。

假设在A、B之间增加节点D,那么原来落到B的部分数据将落到节点D,因此只有B受到影响,其他节点不会受到影响。

为什么Redis是使用哈希槽而不是一致性哈希呢?

  • 当发生扩容时候,Redis可配置映射表的方式让哈希槽更灵活,可更方便组织映射到新增server上面的slot数,比一致性hash的算法更灵活方便。

  • 在数据迁移时,一致性hash 需要重新计算key在新增节点的数据,然后迁移这部分数据,哈希槽则直接将一个slot对应的数据全部迁移,实现更简单。

  • 可以灵活的分配槽位,比如性能更好的节点分配更多槽位,性能相对较差的节点可以分配较少的槽位。

为什么Redis Cluster哈希槽数量是16384?

image.png

  • Redis节点间通信时,心跳包会携带节点的所有槽信息,它能以幂等方式来更新配置。如果采用 16384 个插槽,占空间 2KB (16384/8);如果采用 65536 个插槽,占空间 8KB (65536/8)。

  • Redis Cluster 不太可能扩展到超过 1000 个主节点,太多可能导致网络拥堵。

  • 16384 个插槽范围比较合适,当集群扩展到1000个节点时,也能确保每个master节点有足够的插槽

参考资料

cloud.tencent.com/developer/a…