分布式状态服务架构设计

  1. 状态服务定义
  2. hash取模数据分片
  3. 分段hash
  4. 一致性hash
  5. redis hash 槽
  6. 一致性 hash 应用

当设计分布式状态服务,需要请求落在持有数据的正确的状态服务节点(粘性负载均衡),所以不能像无状态服务一样随意扩缩容,需要考虑到数据分片和负载均衡策略。

hash 取模数据分片

hash loadbalance

如图当状态服务节点数量为3个,使用hash取模算法hash(key) % 3对客户端唯一key进行负载均衡,确保每次来自同一客户端的请求路由到同一个状态服务数据节点。

哈希取模分片的核心问题,对扩容不友好,扩容的时候数据迁移规模太大。

比如把节点从3个扩展到4个,分片算法调整为hash(key) % 4,之前存储的大量数据需要重新计算存储节点并迁移,对所有数据重新进行分布。

若一定要采用哈希取模分片,建议采用多倍扩容的办法,如原先的3个节点扩容到6个节点,只需要迁移50%的数据,减少数据迁移量。

数据固定分片

如果分片键均衡增长,也可以采用固定数据分片策略。

hash loadbalance

如图,每个节点负责一个号段的请求,这里为1-300w, 300w-600w, 600w-1000w,当号段超过1000w时增加新的节点,对现有节点无影响无需数据迁移。

客户端需要存储和及时更新号段与节点的映射关系。

Redis Cluster的分片策略

Redis 集群采用哈希槽 slots 对数据进行分片,固定16384个哈希槽,比如对于三个 Redis 节点,哈希槽的分配方式如下:

  • 节点A拥有 0-5500 哈希槽
  • 节点B拥有 5501-11000 哈希槽
  • 节点C拥有剩余的 11001-16383 哈希槽

key 与 redis 节点之间的映射关系,使用CRC16哈希算法对key运算得到哈希值,对哈希槽数 16383 进行取模,得到key对应的哈希槽,通过哈希槽映射到对应的redis节点。

当集群扩容时,通过 reshard(重新分配),将现有节点的任意数量slot哈希槽及对应的数据迁移给新的节点。

一致性哈希

一致性哈希算法,可以保证当机器增加或者减少时,节点之间的数据迁移只限于两个节点之间,不会造成全局的网络问题。

consistent hash

如图,一致性哈希通过哈希环,将 A、B、C 三个节点通过哈希值映射到哈希环上对应位置,张三发出请求,通过hash(张三)得到哈希值,顺时针查找请求落在节点A上。

假如集群扩容节点D加入,哈希值为图中位置,此时只需将A节点中数据重新hash,将(B, D] 段迁移到D节点即可,其他节点不受影响。

虚拟节点

当集群节点数量较少时,一致性hash会导致负载不均衡,上图中明显节点A和B的负载更大。

通过引入虚拟节点,解决哈希环偏斜问题,让集群中的节点尽可能的多。