本文是对工作中碰到的集群 Hash 分片方式的一点总结与思考。常见的集群 Hash 分片方式主要有:
- 简单Hash
- 一致性Hash
- 基于Slot
简单Hash的集群分片方式
思路是对每个请求计算出Hash值(一个整型的数值),然后用Hash值与服务节点数量N,做取模操作来确定请求应该被路由到哪个服务节点上去。其中需要对每个服务节点从0到N进行编号。下图是简单Hash分片方式集群的示意图:
很明显这种分片方式严重依赖服务节点的数量,如果进行扩容或者减容操作,所有请求对应的服务节点都可能发生变动,如果服务节点是带有状态的存储服务(比如Reids、Mysql等),数据Rehash将是一个复杂而浩大的工作。
所以简单Hash分片方式并不适合带有状态的集群,相反对于无状态的集群,它是一种很好的分片方式。
一致性Hash的集群分片方式
一致性Hash算法可以缓解Rehash的量。它的简要原理如下,首先有一个Hash环,它代表了整个数据集的Hash空间,也就是说所有的数据或者请求的哈希值都在Hash空间的范围内,并且一个服务节点管辖从它到下一个服务节点之间的Hash值。其次所有的服务节点散列在Hash环上。最后请求过来后计算Hash值,该请求的Hash值落在哪个服务节点的管辖范围,请求就被路由到哪个服务节点。
同样讨论扩容减容的问题,扩容减容因为只会影响一部分服务节点的管辖范围,所以相交于简单Hash的方式,Rehash的工作要减少不少,但Rehash本身还是较复杂的。
基于Slot的集群分片方式
最后来看基于Slot的分片方式。大概思路是在服务节点的基础上抽像出来一层叫Slot,每个服务节点包含一部分Slot,在这个集群中Slot的数量不能改变。每个请求或者数据经过Hash后映射到Slot上,在根据Slot与服务节点的归属关系路由到服务节点。大意如下如:
这种方式主要是为了解决简单Hash分片方式导致的扩容减容问题。因为种种分片方式的集群,在服务端都会提供在集群间迁移Sot的接口。这样当扩容减容的时候迁移Slot就达到了目的,最重要的是因为集群Slot数量是不变的,扩容减容不需要Rehash,这极大的减小了扩容减容操作的复杂性。
小结一下,对于无状态的服务,简单Hash分片方试是一种较好的选择,因为扩容或者缩容的时候不需要处理状态变更。而对于有状态的集群类型,基于Slot的分片方式是一种很好的方式,因为状态变更可以封装到对slot的操作中。
以上看似简单的分片方式,在分布式系统中的应用是十分广泛的,包括有状态的Redis-Cluster、Kafka等,还有无状态的Storm、Hadoop等。
本作品采用 知识共享署名 4.0 国际许可协议 进行许可, 转载时请注明原文链接。