3分钟学会一致性hash算法

2016/09/27 Swift

本文介绍一致性hash算法的基本原理。他是swift中ring的理论基础,在下一blog中,会进一步介绍它在swift中的应用。

普通Hash算法

假设有四台存储节点(Drive 0, 1, 2 and 3),有4个object需要存储在上面。用普通的Hash算法实现方法如下:

  • Step 1: 对象名称account/container/object作为键,使用MD5散列算法得到一个散列值key,
  • step 2: 用第一步计算得到的key mod N 得到存储节点的号(0,1,2 and 3)

    N:为存储节点的数量,本例中N=4.

存储节点和object的映射关系:

OBJECT HASH VALUE (HEXADECIMAL) MAPPING VALUE DRIVE MAPPED TO
Image 1 b5e7d988cfdb78bc3be1a9c221a8f744 hash(Image 1) % 4 = 2 Drive 2
Image 2 943359f44dc87f6a16973c79827a038c hash(Image 1) % 4 = 3 Drive 3
Music 1 4b46f1381a53605fc0f93a93d55bf8be hash(Image 1) % 4 = 1 Drive 1
Music 2 508259dfec6b1544f4ad6e4d52964f59 hash(Image 1) % 4 = 0 Drive 0

普通hash算法的缺点是: 如果N增加1,映射关系变成了key mod (N+1),会导致整个哈希环的重新分配,几乎全部的数据都要重新移动一遍,这样会造成极大的性能开销。

一致性哈希算法

一致性哈希算法实现

  • Step 1: 每个节点的机器名或者是IP地址最键,使用MD5散列算法得到一个散列值key,并将其分配到一个圆环区间上(这里取0-2^32)。
  • Step 2: 每个对象名称account/container/object作为键,使用MD5散列算法得到一个散列值key,也将其分配到这个圆环上。
  • Step 3: 从对象映射到的位置开始顺时针查找,将对象保存到找到的第一个节点上。

虚拟节点

平衡性是hash算法的一个重要指标,平衡性是指对于存储的所有对象,尽可能均匀的分到所有的设备上去。

注: 虚拟节点在swift里叫partion。

用上面提到的一致性哈希算法存储对象,当节点数量比较少时,平衡性会很差,所以引入了虚拟节点的概念来解决这个问题。

对每一个存储节点计算多个哈希,每个计算结果,都在ring中放置一个存储节点,称为虚拟节点。那么多个hash值该如何计算呢?在服务器ip或主机名的后面增加编号,然后
在计算Hash。比如一个存储节点对应三个虚拟节点,总共三个存储节点,计算方法如下:

  • Step 1: 分别以“A#1”、“A#2”、“A#3”做键,用MD5散列算法计算其散列值key,并将其分配到一个圆环区间上。

  • Step 2: 分别以“B#1”、“B#2”、“B#3”做键,用MD5散列算法计算其散列值key,并将其分配到一个圆环区间上。

  • Step 3: 分别以“C#1”、“C#2”、“C#3”做键,用MD5散列算法计算其散列值key,并将其分配到一个圆环区间上。

  • Step 4: 每个对象名称account/container/object作为键,使用MD5散列算法得到一个散列值key,也将其分配到这个圆环上。

  • Step 5: 从对象映射到的位置开始顺时针查找,将对象保存到找到的第一个节点上。

对象和存储节点的映射

加入虚拟节点后,一个实际的存储节点对应若干个虚拟的节点,对象和实际的存储节点的映射关系如下:对象——虚拟节点——设备,如下图所示:

Search

    Post Directory