接触到这个一致性哈希算法是在腾讯音乐的讲座中,用于在线扩容

如图中的例子,本来只有group0和group1,现在要增加一个group2用于推送新的数据,如果使用不满足单调性要求的hash方法,首先向group2推送数据,然后向group0推送数据,如下图所示:

 此时,group1还未更新,group0和group2已经更新,在这个时间段,数据docC是丢失的。

但是如果满足单调性,在增加一个group的情况下,原来在group0的docC只会在原来的group0或者新的group2,不可能出现在group1,因此不会出现上述情况。

转自 jump consistent hash的逻辑详解 - 知乎,仅用于自己学习使用,如有侵权请联系删除

目录

Ⅰ. 一致性哈希的特点

1.1 一致性

1.2 均匀性

1.3 举例

Ⅱ. 构造满足一致性,但不满足均匀性的哈希算法

2.1 方法1

2.2 方法2

2.3 方法1和方法2都不满足“均匀性”

Ⅲ. 调整算法中的参数,使其满足等均匀性

3.1 让方法1满足均匀性

3.2 让方法2满足均匀性

总结


Ⅰ. 一致性哈希的特点

在《A Fast, Minimal Memory, Consistent Hash Algorithm》这篇论文中,作者提出,一致性哈希最重要的两个特性是“一致性”和“均匀性”。

1.1 一致性

当给哈希增加一个新桶时,需要对已有的key进行重新映射。一致性的意思是,在这个重新映射的过程中,key要么保留在原来的桶中,要么移动到新增加的桶中。如果key移动到原有的其他桶中,就不满足“一致性”了。

这是一致性哈希区别于传统哈希的特征,传统的哈希在增加一个新桶时,一般会对key进行随机重新的随机映射,key很可能移动到其他原有的桶中。

1.2 均匀性

均匀性是指key会等概率地映射到每个桶中,不会出现某个桶里有大量key,某个桶里key很少甚至没有key的情况。

这是一致性哈希和传统哈希都有的特征。

1.3 举例

理解“一致性”和“均匀性”是理解后文的基础,这里举几个例子来加深理解:

  • 满足“一致性”,不满足“均匀性”的哈希

例1:增加桶4后,所有key仍保留在原有桶中,满足一致性;但桶中的key分部不均匀,不满足均匀性

例2:增加桶4后,所有key移动到新桶中,满足一致性;但桶中的key分部不均匀,不满足均匀性

例3:增加桶4后,原有桶1中的key保持不变,桶2和桶3中的元素移动到新桶中,满足一致性;但桶中的key分部不均匀,不满足均匀性

  • 不满足“一致性”,满足“均匀性”的哈希

例4:增加桶4后,各key均匀分布,满足均匀性;但key_4从原有的桶1移动到桶2,不满足一致性

  • 同时满足“一致性”和“均匀性”的哈希

例5:增加桶后,各key均匀分布,满足均匀性;并且key没有在原有的桶中移动,也满足一致性

Ⅱ. 构造满足一致性,但不满足均匀性的哈希算法

我们先看看“一致性”的要求:当增加新桶时,原有桶中的key要么保留在原有的桶中,要么移动到新增的这个桶中。

假设一致性哈希函数为  ,其中 key为要放入元素的键值,n 为桶的个数,函数返回值是给 key分配的桶id(从0开始),返回值的范围为 [0,n-1]。那么根据“一致性”的要求,有如下的递推公式

有了这个递推公式,我们就很方便实现满足“一致性”的哈希算法了。

2.1 方法1

直接使用这个递推公式。开始桶的总数为1,所有的key都放在第0个桶中。然后每增加一个桶,生成一个随机数,当这个随机数为奇数时,将key放在保持在原始桶中,当这个key为偶数时,将key移动到新增的桶中。

具体C++代码如下:

unsigned int ch(unsigned int key, unsigned int n)
{srand(key);unsigned int id = 0; // 桶数为1时,所有key放到第0个桶中for (unsigned int i = 1; i < n; i++){// 每增加一个桶,生成一个随机数if (rand() % 2 == 1){id = id; // 如果随机数为奇数,key仍然保留在原来的桶中}else{id = i; // 如果随机数为偶数,将key移动到新分配的桶中}}return id;
}

注意,由于使用key作为随机数的种子,因此一旦key和n确定了,函数的返回值也就是确定的。并且当函数参数为n和参数为n-1时,循环过程中的前面几步生成的随机数都是一样的。

2.2 方法2

开始桶的总数为1,所有的key都放在第0个桶中,同时生成一个大于当前桶数的随机数。每增加一个新桶时,判断当前桶总数是否超过这个随机数。如果未超过(桶数小于或等于这个随机数),则将key保留在原来的桶中;如超过,则将key移动到新增加的桶中,同时重新生成一个大于当前桶数的随机数,后续增加新桶时,使用和前面相同的逻辑进行判断。

和方法1一样,我们也使用key作为随机数的种子,因此一旦key和n确定了,函数的返回值也就是确定的。

具体C++代码如下:

unsigned int ch(unsigned int key, unsigned int n)
{srand(key);unsigned int id = 0;unsigned int fence = rand();while (n > fence){id = fence;fence = id + rand();}return id;
}

这个代码初看可能不太直观,我们一步一步来分析:

  • 当n=1时,可以看出函数的返回值id是0,同时假设生成一个随机数fence=3
  • 当n=2, 3时,因为随机数种子不变,所以开始生成的随机数fence也是3,这个时候函数的返回值id仍然是0
  • 当n=4时,因为因为随机数种子不变,开始fence=3,所以n>fence,进入循环中。进入循环后id=3,并假设生成的新fence=3+5=8。此时n<新生成的fence,跳出循环返回id=3
  • 当n=5, 6, 7, 8时,因为因为随机数种子不变,开始fence=3,所以n>fence,进入循环中。进入循环后id=3,新生成的fence=8。此时n=新生成的fence,跳出循环返回id=3
  • 当n=9时,前面都是重复n=5, 6, 7, 8的步骤。在最后一步时,因为n=9,fence=8,满足n>fence,会再次进入循环,此时id=8,假设新生成fence=8+2=10。此时会跳出循环返回id=8
  • ……

可以看出,这个方法也是满足递推公式的。当输入参数为n时,函数的返回值只有两个分支:要么和参数为n-1时相同,要么函数的返回值是n-1。而这两个方法,正好对应论文《A Fast, Minimal Memory, Consistent Hash Algorithm》中O(N)和O(logN)的两个算法,区别仅在于生成随机数的方式、函数返回值走那个分支的判断方法。

2.3 方法1和方法2都不满足“均匀性”

接下来我们分析下这两个方法是否满足“均匀性”。哈希的“均匀性”要求对于任意的key,当桶数为n时,key被分配到任意桶中的概率都是1/n。

对于方法1,我们分析下当桶的总数为3时,key被分配到第0个桶中的概率:

当桶数为3时,循环会执行2次,如果要key被分配到第0个桶,要求两次生成的随机数都是奇数,其概率是1/4。很明显不满足“均匀性”

对于方法2,我们分析下当桶的总数为2时,key被分配到第0个桶中的概率:

当桶的总数为2时,如果生成的随机数fence大于或等于2,那么不会进入循环体,key也就被分配到第0个桶中了。因为rand()的返回值均匀分布在[0, RAND_MAX]之间,因此生成的随机数fence大于或等于2的概率是非常大的,几乎接近1。因此这个情况下key被分配到第0个桶中的概率接近1。也不满足“均匀性”。

Ⅲ. 调整算法中的参数,使其满足等均匀性

这部分,我们并不去推导如何设计算法中参数,使满足均匀性。而是直接使用论文中的参数,并证明这个参数能满足均匀性。也就是说,本部分不讲推导过程,仅讲证明过程。

哈希的“均匀性”要求对于任意的key,当桶数为n时,key被分配到任意桶中的概率都是1/n。

3.1 让方法1满足均匀性

先回顾下方法1的思路。

方法1:直接使用这个递推公式。开始桶的总数为1,所有的key都放在第0个桶中。然后每增加一个桶,生成一个随机数,当这个随机数为奇数时,将key放在保持在原始桶中,当这个key为偶数时,将key移动到新增的桶中

根据前面的分析,由于增加桶时,key移动到新桶和保留在原始桶中的概率是1/2,因此不满足“均匀性”。那为了让其满足“均匀性”,我们需要调整key移动到新桶和保留在原始桶中的概率。

假设当前桶数为k,如果新增加一个桶,key移动到新桶的概率为1/(k+1),那么算法就可以满足“均匀性”了。我们可以一步一步进行证明:

首先对n=1、2、3这个特殊情况进行推导:

  • 首先,当桶总数n=1时,key分配到第0个桶中的概率是1
  • 新增一个桶,此时n=2,key被分配到新桶(第1个桶)中的概率是1/2,保留在原桶中的概率也是1/2
  • 再新增一个桶,此时n=3,key被分配到新桶(第2个桶)中的概率是1/3,保留原桶(第0或1个桶)中的概率是1/2 * 2/3 = 1/3

然后我们可以有更通用的推导:

  • 当n=k时,key被分配到每个桶中的概率是1/n
  • 再新增一个桶,此时n=k+1,key被分配到新桶(第k个桶)中的概率是1/(k+1),保留原桶(第0或1或……或k-1个桶)中的概率是1/k * k/(k+1) = 1/(k+1)。此时key被分配到每个桶的概率仍然为1/n

因此方法1的代码修改如下:

int ch(int key, int n)
{random.seed(key);int id = 0;for (int j = 1; j < n; j++){if (random.next() < 1.0/(j+1)){id = j;}}return id;
}

3.2 让方法2满足均匀性

先回顾下方法2的思路

方法2:开始桶的总数为1,所有的key都放在第0个桶中,同时生成一个大于当前桶数的随机数。每增加一个新桶时,判断当前桶总数是否超过这个随机数。如果未超过(桶数小于或等于这个随机数),则将key保留在原来的桶中;如超过,则将key移动到新增加的桶中,同时重新生成一个大于当前桶数的随机数,后续增加新桶时,使用和前面相同的逻辑进行判断。

int ch(int key, int n)
{random.seed(key);int b = 0;int f = 0;while (f < n){b = f;r = random.next();f = floor((b+1)/r)}return b;
}

总结

本文从另外一个角度来解释了jump consistent hash,希望能够帮助大家理解这个很厉害的算法。

另外,在最后也提一下jump consistent hash在实际使用中的缺点和解决方案。和传统的环形一致性哈希相比,这个算法有两个缺点:

  1. 不支持设置哈希桶的权重
  2. 仅能在末尾增加和删除桶,不能删除中间的哈希桶

我们可以采用计算机科学最传统的方法(增加一个中间层)来解决这两个问题:增加一层虚拟桶,使用jump consistent hash来将   分配到虚拟桶中,然后在虚拟桶和实际桶之间建立一个映射关系。这样我们就可以通过映射关系来设置实际桶的权重;也可以在任意位置删除和添加实际桶,只需要维护好映射关系即可。当然,这样做的代价就是,算法本来可以的无内存占用的,现在需要有一块内存来维护映射关系了。

一致性哈希算python包jump-consistent-hash · PyPI

Google Jump Consistent Hash 一致性哈希算法相关推荐

  1. 一致性哈希算法学习及JAVA代码实现分析

    1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...

  2. c语言实现一致性hash算法,一致性哈希算法(Consistent Hashing)

    应用场景 这里我先描述一个极其简单的业务场景:用4台Cache服务器缓存所有Object. 那么我将如何把一个Object映射至对应的Cache服务器呢?最简单的方法设置缓存规则:object.has ...

  3. 白话解析:一致性哈希算法 consistent hashing

    在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经典的分布式缓存的 ...

  4. 一致性hash算法虚拟节点_一致性哈希算法——虚拟节点

    一致性哈希算法--虚拟节点 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具体的节点上,如果采用普通的hash方法,将数据映射到具体的节点上,如key%N,key是 ...

  5. 【转载】一致性哈希算法(consistent hashing)

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...

  6. 理解一致性哈希算法(consistent hashing)

    出处:http://blog.csdn.net/cywosp/article/details/23397179     一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法, ...

  7. java一致性hash api_一致性哈希算法学习及JAVA代码实现分析

    戳上面的蓝字关注我们哦! 本文作者:hapjin 欢迎点击下方阅读原文 1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式 ...

  8. 《一切皆是映射:代码的本质》一致性哈希算法(consistent hashing)

    一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致 ...

  9. 【hash】哈希算法、哈希碰撞、一致性哈希

    一.hash算法 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长 ...

最新文章

  1. linux mariadb
  2. Android学习摘要一之Android历史
  3. oracle表分区失效14400,Oracle11g:分区表数据操作出现ORA-14400异常处理详解
  4. oracle rodo 查看大小,Exadata — platforma bazodanowa | Oracle Polska
  5. UVALive 4223 Trucking 二分+spfa
  6. 安装 samba 记录
  7. android 好看的计算器,从未见过如此丑的计算器 – 计算管家 #Android
  8. 链表最小结构(C++版本)
  9. c语言如何框出视频或图像中的车辆,视频图像中的车辆检测跟踪和分类
  10. 架构师的“功夫在诗外”之二
  11. bulk of the 用法_必须牢记的初中英语10大词类详解用法考点,超全讲解!
  12. Boost电路实战详解!(高效率同步整流,PID闭环追踪)
  13. 《GAMES203:三维重建和理解》1 三维视觉(3D Vision)介绍
  14. 中国大学慕课mooc毛概考试答案参考
  15. 关于windows10在学习爬虫是用到appium配置java的jdk出现了,javac不是内部命令的解决方法(¥57)
  16. EasyFlash 里的 EF_WRITE_GRAN
  17. 联想笔记本修复计算机还原系统失败,联想电脑重置电脑失败怎么办
  18. 用于长延迟多径衰落环境下的强化UF-OFDM
  19. 探讨企业即时通讯软件的价值
  20. 电脑开机在一会儿未使用卡死解决方法

热门文章

  1. 《Java并发编程实践》读书笔记
  2. css控制div显示/隐藏方法及2种方法比较原码[转]
  3. OpenCV-闭运算(CLOSE)
  4. c语言健身房会员管理系统,健身房会员管理系统c#.net
  5. 开了立体声混音仍然不能内录_蓝牙音箱有个功能很鸡肋,用好了秒变HIFI立体声...
  6. c# 网口相机可以通过_c# Halcon 实现通过相机图像采集及处理
  7. yum安装ruby_CentOS 7下配置Ruby语言开发环境的方法教程
  8. mysql查看现在使用的引擎_如何查看MySQL的当前存储引擎?
  9. python实践项目(十一)
  10. HEVC里面CU与TU打印到屏幕及提取到txt文本