一文读懂一致性哈希

1.哈希简介

在开始说一致性哈希之前,我们先来了解一下什么是哈希。

1.1 概念

哈希(Hash)亦称作散列或杂凑,指对任意一组输入数据进行计算,得到一个固定长度的输出。

这种转换是一种压缩映射,也就是说散列值的空间通常远小于输入的空间。不同的输入可能会散列成相同的输出,这种现象称为碰撞。

简单地说哈希就是一种将任意长度的消息压缩到某一固定长度消息的函数。

1.2 性质

哈希算法最重要的特点有:

  • 确定性:相同的输入一定得到相同的输出,也就是说哈希值不同,对应的原始输入一定不同。
  • 碰撞性:不同的输入可能得到相同的输出。
  • 不可逆性:无法逆向演算回原本的数值。

1.3 常见应用场景

哈希的本质是给定输入与哈希算法,生成一个唯一映射。一般用于以下几个场景:

(1)文件校验

我们比较熟悉的校验算法有奇偶校验和 CRC 校验,这 2 种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。

比如哈希算法 MD5 一般用于生成消息的数字指纹,使它成为应用最广泛的一种文件完整性校验算法,不少类 Unix 系统都有提供计算 MD5 的命令,比如 Linux 的 md5sum

(2)数字签名

哈希算法是现代密码体系的一个重要组成部分。在非对称加密体系中,哈希算法可对消息计算产生摘要,再对摘要使用发送方的私钥加密生成数字签名。数字签名主要有两个作用:

  • 对数字签名使用发送方的公钥解密,根据解密是否成功用于身份认证;
  • 将解密后的消息摘要与收到的消息的摘要进行比对,用于校验消息完整性。

(3)密码保护

散列算法也常被用来加密密码字符串,由于散列算法所计算出来的散列值具有不可逆(无法逆向演算回原本的数值)的性质,因此可有效地保护密码。

(4)分布式寻址

在分布式系统中,一般需要根据键值映射到对应的机器。比如在分布式存储中,需要根据存储数据的键值为其分配存储节点,这时就需要进行分布式寻址。此时可以利用哈希算法来完成数据键值到节点的唯一映射。

1.4 常见哈希算法

  • MD4

MD4(RFC 1320)是 MIT 教授 Ronald L. Rivest 在 1990 年设计的一种消息摘要算法,其摘要长度为 128 位。基于 32 位操作数的位操作来实现,适用在 32 位字长的处理器上。

  • MD5

MD5(RFC 1321)是由 Ronald Rivest 于1991 年提出的对 MD4 的改进版本。它对输入仍以 512 位分组,其输出是 4 个 32 位字的级联,与 MD4 相同。

MD5 的实现比 MD4 复杂,速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。

  • SHA 家族

SHA 是由美国国家标准技术研究所(NIST)和美国国家安全局(NSA)一同设计的散列算法。其中 SHA1 对任意长度的输入,生成长度为 160bits 的散列值,抗穷举性更好。SHA1 设计时参考了 MD4 的实现原理,并且模仿了该算法。

2.常见负载均衡算法

在解决分布式系统负载均衡的问题时,可供选择的算法有很多。

2.1 静态负载均衡算法

  • 轮询(Round Robin)
  • 加权轮询(Weighted Round Robin)
  • 随机(Random)
  • 加权随机(Weighted Random)
  • 源地址哈希(Source IP Hash)

2.2 动态负载均衡算法

  • 最少连接(Least Connections)
  • 加权最少连接(Weighted Least Connections)
  • 响应时间(Response Time)
  • 加权响应时间(Weighted Response Time)
  • 基于资源(Resource based)

2.3 问题

其中源地址哈希是最为常用的算法。典型的应用场景是:有 N 台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分发到每台服务器上,每台机器负责 1/N 的服务,起到负载均衡的作用。

常用的做法是对 Hash 结果取余 (Hash(IP)%服务节点数),对节点编号从 0 到 N-1,按照余数将请求分发到对应编号的节点上。

此种做法虽然简单,但容错和扩展性很差,当新增或者节点宕机时,请求与服务节点的映射关系会大量失效,对于有状态的系统而言,比如存在本地缓存,那么将会出现大量缓存失效,这通常是不可接受的。

3.一致性哈希

3.1 由来

为了解决常见负载均衡算法的容错和扩展性差的问题,一致性哈希应运而生。

一致性哈希(Consistent Hashing)在 1997 年由麻省理工学院的 David Karger 等人为解决分布式 Cache,在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中提出。设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和 CARP 十分类似。一致性哈希修正了 CARP 使用的简单哈希算法带来的问题,使得 DHT 可以在 P2P 环境中真正得到应用。

在 Memcached、Key-Value Store 、Bittorrent DHT、LVS 中都采用了一致性哈希,可以说一致性哈希是分布式系统负载均衡的首选算法。

3.2 特性

考虑到分布式系统每个节点都有可能失效,并且新的节点很可能动态的增加进来,如何保证当系统的节点数目发生变化时仍然能够对外提供良好的服务,这是值得考虑的。尤其实在设计分布式缓存系统时,如果某台服务器失效,对于整个系统来说如果不采用合适的算法来保证一致性,那么缓存于系统中的所有数据都可能会失效(即由于系统节点数目变少,客户端在请求某一对象时需要重新计算其 Hash 值(通常与系统节点数目有关),由于 Hash 值已经改变,所以很可能找不到保存该对象的节点),因此一致性 Hash 就显得至关重要。

在论文《Consistent hashing and random trees》提出了在动态变化的 Cache 环境中,良好的一致性哈希算法具有以下四个特性:

(1)均衡性(Balance)。

在一致性哈希中,节点和请求被哈希到一个连续的哈希环上。每个节点负责哈希环上一段范围内的请求。节点和请求在哈希环上的分布应该是均匀的,那么任意相邻两节点的请求量应该是均衡的,以保证节点的负载均衡。

在在服务节点很少时,可以使用虚拟节点避免请求倾斜(负载不均衡)。

(2)单调性(Monotonicity)。

单调性指如果已经有一些请求通过哈希分派到了相应节点进行处理,那么当节点发生增减,比如有新节点加入到系统,应保证原有请求可以被映射到原有的或者新的节点,而不会被映射到原来的其它节点。这个通过上文新增节点可以证明,新增 Node X 后,只有 Object C 被重新分派到 Node X,其它请求路由不变。

(3)低分散性(Low Spread)

在分布式环境中,终端有可能看不到所有的节点,而是只能看到其中的一部分。当终端希望通过哈希过程将请求映射到节点上时,由于不同终端所见的节点有可能不同,从而导致哈希的结果不一致,最终的结果是相同的请求被不同的终端映射到不同的节点。这种情况显然是应该避免的。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。

(4)低负载(Low Load)

负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的请求映射到不同的节点,那么对于一个特定的节点而言,也可能被不同终端的不同请求映射。

与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低节点的负载。

3.3 实现

原理

一致性哈希算法也用了取模运算,但与普通哈希算法不同。

普通哈希算法是对节点的数量进行取模运算,而一致哈希是对固定值 2^32 进行取模运算。

简单来说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,假设某哈希函数 H 的值空间为 0-2^32-1(即哈希值是一个 32 位无符号整型),整个空间按顺时针方向组织,哈希空间环如下图所示:

下一步将各个服务器使用 Hash 算法计算出一个哈希值,具体可以选择服务器的 IP 或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。这里假设将上文中有四台服务器使用 IP 地址哈希后在环空间的位置如下:

当用户在客户端进行请求时候,首先根据 Hash(Key) 计算路由规则(Hash 值),然后看 Hash 值落到了 Hash 环的哪个地方,根据 Hash 值在 Hash 环上的位置顺时针找距离最近的服务器作为路由节点。

例如我们有 Object A、Object B、Object C、Object D 四个数据对象,经过哈希计算后,在环空间上的位置如下:

根据一致性哈希算法,数据 A 会被定为到 Node A 上,B 被定为到 Node B 上,C 被定为到 Node C 上,D 被定为到 Node D上。

容错

现假设 Node C 不幸宕机,可以看到此时对象 A、B、D 不会受到影响,只有 C 对象被重定位到 Node D。一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。

扩展

下面考虑另外一种情况,如果在系统中增加一台服务器 Node X,如下图所示:

此时对象 A、B、D 不受影响,只有对象 C 需要重定位到新的 Node X 。一般的,在一致性哈希算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它数据也不会受到影响。

综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

虚拟节点

如果服务节点太少,一致性哈希算法容易因为节点分部不均匀而造成请求倾斜问题。例如系统中只有两台服务器,其环分布如下:

此时必然造成大量数据集中到 Node A 上,而只有极少量会定位到 Node B 上。为了解决这种请求倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希值,每个计算结果对应的位置都放置一个服务节点,称为虚拟节点。

具体做法可以在服务器 IP 或主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3” 的哈希值,于是形成六个虚拟节点:

同时请求定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到 Node A 上。这样就解决了服务节点少时请求倾斜的问题。在实际应用中,通常将虚拟节点数设置为 32 甚至更大,因此即使很少的服务节点也能做到相对均匀的流量分布。

4.小结

一致性 Hash 算法主要用于解决分布式系统中请求到节点的映射。每个节点都有可能失效,并且新的节点很可能动态地加进来,如何保证当系统的节点数目发生变化的时候,我们的系统仍然能够对外提供良好的服务,一致性 Hash 算法可以有效地解决这个问题!


参考文献

Consistent hashing - Wikipedia
一致性hash算法释义 - 博客园
分布式算法(一致性Hash算法) - 博客园
9.4 什么是一致性哈希? - 小林coding
一文讲透一致性哈希的原理和实现 - 万俊峰

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值