分布式, 算法, 一致性哈希,

一致性哈希算法

波斯王子 波斯王子 Follow Aug 29, 2021 · 1 min read
一致性哈希算法
Share this

Raft 算法实现了 KV 存储,虽然领导者模型简化了算法实现和共识协商,但写请求只能限制在领导者节点上处理,导致了集群的接入性能约等于单机,那么随着业务发展,集群的性能可能就扛不住了,会造成系统过载和服务不可用,这时我们就要通过分集群,突破单集群的性能限制。

比如可以加个 Proxy 层,由 Proxy 层处理来自客户端的读写请求,接收到读写请求后,通过对 Key 做哈希找到对应的集群就可以了啊。是的,哈希算法的确是个办法,但它有个明显的缺点:当需要变更集群数时(比如从 2 个集群扩展为 3 个集群),这时大部分的数据都需要迁移,重新映射,数据的迁移成本是非常高的。一致性哈希(Consistent Hashing)能够解决哈希算法数据迁移成本高这个痛点,也能实现数据访问的冷热相对均匀。

使用哈希算法的问题

如果服务器数量发生变化,基于新的服务器数量来执行哈希算法的时候,就会出现路由寻址失败的情况,Proxy 无法找到之前寻址到的那个服务器节点。解决这个问题的办法,在于我们要迁移数据,成本是非常高的(可能要迁移绝大部分数据)。

使用一致哈希实现哈希寻址

哈希算法是对值的哈希在节点的数上量进行取模运算,而一致哈希算法是对值和节点都在 2^32 上进行取模运算。一致哈希算法,将整个哈希值空间组织成一个虚拟的圆环,也就是哈希环

通过执行哈希算法,先将节点映射到哈希环上(比如选择节点的主机名作为参数执行哈希函数),当需要对指定 key 的值进行读写的时候,你可以通过下面 2 步进行寻址:

  1. 将 key 作为参数执行哈希函数计算哈希值,并确定此 key 在哈希环上的位置;
  2. 从这个位置沿着哈希环顺时针“行走”,遇到的第一节点就是 key 对应的节点。

总的来说,使用了一致哈希算法后,扩容或缩容的时候,都只需要重定位环空间中的一小部分数据。也就是说,一致哈希算法具有较好的容错性和可扩展性。

虚拟节点,实现数据访问的冷热相对均匀

在哈希寻址中常出现这样的问题:客户端访问请求集中在少数的节点上,出现了有些机器高负载,有些机器低负载的情况,在一致哈希中,如果节点太少,也容易因为节点分布不均匀造成数据访问的冷热不均,也就是说大多数访问请求都会集中少量几个节点上,有什么办法能让数据访问分布的比较均匀呢?答案就是虚拟节点

虚拟节点就是对每一个服务器节点计算多个哈希值,在每个计算结果位置上,都放置一个虚拟节点,并将虚拟节点映射到实际节点(比如,可以在主机名的后面增加编号)。增加虚拟节点后,节点在哈希环上的分布就相对均匀了,这样就解决了节点访问冷热不均的问题。

当节点数越多的时候,使用哈希算法时,需要迁移的数据就越多,使用一致哈希时,需要迁移的数据就越少

一致哈希本质上是一种路由寻址算法,适合简单的路由寻址场景。比如在 KV 存储系统内部,它的特点是简单,不需要维护路由信息。

思考

Raft 集群具有容错能力,能容忍少数的节点故障,那么在多个 Raft 集群组成的 KV 系统中,如何设计一致哈希,实现当某个集群的领导者节点出现故障,并选举出新的领导者后,整个系统还能稳定运行呢

相比“值到节点”的一级映射,可以做两级映射,“值到集群,集群到领导者节点”,通过Raft的节点故障容错能力,来避免数据迁移。在实际系统中,如果不采用具有节点故障容错能力的共识算法,一般不会直接将数据写入到下一个节点,而是会有个备份服务器,当节点故障,切换到备节点时,为了实现强一致性,能读取到最新数据,不仅要做一致性对比和数据迁移,还是实现双读,比较复杂。

TiDB、kafka、es 等常见分布式中间件 它们各自如何解决分布式的问题?

Join Newsletter
Get the latest news right in your inbox. We never spam!
波斯王子
Written by 波斯王子 Follow
去读书吧,发现不一样的世界!😉