JumpConsistentHash,一种快速、简单、内存占用最少的一致性hash算法

news/2024/4/26 9:12:14/文章来源:https://blog.csdn.net/qq_34262582/article/details/130320900

  Consistent hashing最早是David Karger在MIT用于分布式缓存时提出的一个概念。对于分布式缓存系统来说,通常数据会分散地分布在不同的node上。而Consistent hashingh的作用就是来定位key->node的关系。本文主要是根据论文简单解释一下JumpConsistentHash的原理和实现。

为什么需要Consistent hashing

  通常来说,在线服务经常会因为请求量波动而需要去做扩缩容。如果用传统的hash方式去做,那就会导致数据分布会重排,那就意味着要做大规模的数据迁移,这显然对在线服务来说是不能接受的。新加一个node,通常只希望每一个node迁移少量一部分数据到新的node,删除一个node同样希望是删除的node重新均匀分配给其他node。而Consistent hashing就是为了解决这种动态数据分布均匀的问题。

JumpConsistentHash的实现

  标准的Consistent hashing实现的思路是把node和key同时hash映射到2^32的环上,再通过顺时针找到key最近的node。这个方式有个缺点是当node很少时,node在环上的分布不均匀,从而导致数据在node的分布不均匀。为了解决这个问题后来又引入了虚拟node的概念。

  传统的实现过于麻烦且复杂,在2014年Google发布了一篇《A Fast, Minimal Memory, Consistent Hash Algorithm》,在这篇论文中Google提出了一种纯数学的方式解决了这个问题,代码只需要仅仅几行。

int32_t JumpConsistentHash(uint64_t key, int32_t num_buckets) {int64_t b = ­1, j = 0;while (j < num_buckets) {b = j;key = key * 2862933555777941757ULL + 1;j = (b + 1) * (double(1LL << 31) / double((key >> 33) + 1));}return b;
}

它的时间复杂度小于ln(n) + 1,后面会给出证明。空间复杂度看代码很显然是O(1)。

JumpConsistentHash的原理

  设ch(key,num_buckets)为当有num_buckets个桶时key的Consistent hashing值。显然,对于任何key k,ch(k,1)为0,因为只有一个桶。为了使Consistent hashing函数平衡,ch(k,2)必须对于一半的k保持为0,另一半的k跳到1。一般来说,ch(k,n+1)必须对于n/(n+1)的key保持与ch(k,n)相同,而对于其他1/(n+1)的key则必须跳到n。

  根据这个思路,我们可以得出一个简单的算法。给定一个key和num_buckets,该算法考虑从1到num_buckets-1的每个连续的桶j,并使用ch(key,j)来计算ch(key,j+1)。在每个桶j处,它决定是否将ch(k,j+1)保持与ch(k,j)相同,或者将其值跳到j。为了跳跃1/(j+1)的key,它生成一个介于0.0和1.0之间的均匀随机数,如果该值小于1/(j+1),则跳跃。代码如下:

int ch(int key, int num_buckets) {random.seed(key);int b = 0; // This will track ch(key, j+1).for (int j = 1; j < num_buckets; j++) {if (random.next() < 1.0 / (j + 1)) b = j;}return b;
}

  这里随着j的增加,跳跃的概率越来越低。所以论文里又想到了一种办法让key直接跳跃到下一个可跳跃的j。

  假设算法正在跟踪特定key的jump bucket。假设b是上一次跳跃的目的地,即ch(k,b)≠ch(k,b+1),且ch(k,b+1)=b。现在,我们想找到下一个跳跃的目的地,即最小的j,使得ch(k,j+1)≠ch(k,b+1),或者等价地算出最大的j,使得ch(k,j)=ch(k,b+1)。我们使用一个随机数j。为了得到对j的概率约束,对于任何i,当且仅当Consistent hashing的值没有改变i时,即当且仅当ch(k,i)=ch(k,b+1)时,我们有j≥i。因此,j的分布必须满足以下条件:

P(j ≥ i) = P(ch(k, i) = ch(k, b+1))

  这个概率P很容易计算。由于P(ch(k,10)=ch(k,11))为10/11,P(ch(k,11)=ch(k,12))为11/12,因此P(ch(k,10)=ch(k,12))为10/11 * 11/12 = 10/12。所以如果n≥m,则P(ch(k,n)=ch(k,m))=m/n。因此,对于任何i>b,有以下结论:

P(j ≥ i) = P(ch(k, i) = ch(k, b+1)) = (b+1) / i 

现在,我们生成一个随机变量r,它在0到1之间均匀分布。由于我们希望P(j≥i)=(b+1)/i,因此我们必须要让r<=(b+1)/i。解不等式得到:仅当i≤(b+1)/r。由于i是j的下限,因此,j=floor((b+1)/r)。使用这个公式,JumpConsistentHash可以通过选择跳跃的目的地来找到ch(key,num_buckets。代码如下:

int ch(int key, int num_buckets) {random.seed(key);int b = ­1; // bucket number before the previous jumpint j = 0; // bucket number before the current jumpwhile (j < num_buckets) {b = j;r = random.next();j = floor((b + 1) / r);}return = b;
}

最后再改成通过LCG来生成随机数就会变成本文开头的那段代码。

JumpConsistentHash的时间复杂度

  该算法的时间复杂度等于循环的执行次数。因为最后一次一定得跳出循环,也就是j >= num_buckets,故最少要执行一次。而每次跳跃的期望小于1/i,所以整体跳跃的期望=Σ 1/i (2 <= i <= n),而这个数值是<ln(n)的,所以最终的复杂度大约是ln(n) + 1。

  论文中没有给出跳跃的期望的证明,可能是因为太简单了,笔者这里简单反证一下。

  假设当前在桶b,根据公式,如果要跳跃到b+1,则r需要在((b+1)/(b+2), 1)这个范围内。如果要跳跃到b+2,则r需要在((b+1)/(b+3), (b+1)/(b+2))这个范围内。以此类推,需要跳到b+n这个位置,则r需要在((b+1)/(b+n+1), (b+1)/(b+n))这个范围。

   故证明每次跳跃的期望小于1/i,等价于证明(b+1)/b+n - (b+1)/(b+n+1) < 1/(b+1),令x=b+1,y=n-1可得:

   x/(x+y) - x/(x+y+1) < 1/x

  最后解得:

x*x < (x+y)(x+y+1)

  因为y=n-1,n>=2,故有y>=1。x=b+1>=1,所以显然上述不等式是成立的。

总结

  JumpConsistentHash提出了一种崭新的思路来解决这类问题。如果已经理解了原理,那不难看出想要增加或者删除node只能在末尾进行操作,这是和传统的实现不一样的地方。但笔者认为这个不是什么很大的缺点,它优秀的复杂度和实现完全可以覆盖掉这个缺点。笔者最近刚好要搭一套分布式缓存服务,直接拿这个上手非常好用。如果还想了解更多细节,比如benchmark,建议看原文。

参考

[1]《A Fast, Minimal Memory, Consistent Hash Algorithm》:https://arxiv.org/pdf/1406.2294.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_102222.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis框架超详解及运用总结

Mybatis 一、什么是Mybatils&#xff1f;二、第一个Mybatils程序2.1、创建springboot工程2.2、准备数据2.3、配置MyBatis2.4、编写SQL语句2.5、单元测试 三、JDBC四、数据库连接池五、lombok六、Mybatis基础操作6.1、删除6.2、新增6.2.1、主键返回 6.3、修改6.4、查询6.4.1、数…

推式配货(Push)、拉式配货(Pull)和配送需求计划(DRP)的区别

随着电子商务的迅猛发展&#xff0c;物流配送服务已然成为企业竞争最为核心的环节&#xff0c;一个全面、完善的物流配送方案&#xff0c;能够帮助企业满足客户交期、节约运输和库存成本&#xff0c;促进各环节沟通&#xff0c;提高生产稳定性。同时&#xff0c;物流配送的许多…

垃圾回收概述

什么是垃圾 垃圾收集&#xff0c;不是Java语言的伴生产物。早在1960年&#xff0c;第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。 关于垃圾收集有三个经典问题&#xff1a; 哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 垃圾收…

9.7 字符串的指针和指向字符串的指针变量

9.7 字符串的指针和指向字符串的指针变量 一.字符串表示形式二.字符串指针做函数参数1.数组名做函数参数2.数组指针做函数参数 三.字符指针变量与字符数组&#xff08;1&#xff09;字符数组是由若干个元素组成&#xff0c;每个元素中存放一个字符。&#xff08;2&#xff09;赋…

[HBZ分享] 小米手机如何解BL锁

第一步&#xff1a; 进入【设置—>我的设备–>全部参数–>连续疯狂的点MIUI版本那一行】 第二步&#xff1a;进入【更多设置–>开发者模式】&#xff0c;打开USB调试 与 USB安装 第三步&#xff1a;进入【更多设置–>开发者模式】&#xff0c;进入【设别解锁状…

人工神经网络

1. 单个神经元 &#x1f351; 神经网络 即 模型 &#x1f364; 输入 四个参数 --> 结果 &#x1f351; 模型训练(学习) 例子 &#x1f351; 模型的输入x 乘 权值ω 减去阈值θ --> 激活函数 f &#x1f351; 输出 yi &#xff08;向下传递 或 直接输出&#xff09; …

JVM性能监测工具-JConsole

JVM性能监测工具-JConsole JConsole工具是JDK自带的图形化性能监控工具。并通过JConsole工具&#xff0c; 可以查看Java应用程序的运行概况&#xff0c; 监控堆信息、 元空间使用情况及类的加载情况等。 JConsole程序在%JAVA_HOM E%/bin目录下 或者你可以直接在命令行对他进…

【致敬未来的攻城狮计划】— 连续打卡第十天:FSP固件库开发及FSP配置详解。

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

手势语言识别模型训练及应用

使用训练集训练模型&#xff0c;使模型能够识别不同手势。 OpenCV-Python环境使用训练集训练模型&#xff0c;使模型能够识别不同手势。系统测试 本项目基于卷积神经网络&#xff0c;通过Python的翻转功能沿垂直轴翻转每个图像&#xff0c;实现手势语言识别的功能。系统流程如图…

数据治理与数据中台架构

随着工业 4.0 时代的到来&#xff0c;传统行业的数字化转型是大势所趋&#xff1b;将数据提高到数据要素层面&#xff0c;让传统的技术在新的场景下发挥出新的作用&#xff0c;是近期研究和探讨的焦点话题。数语科技支持和服务传统行业多年&#xff0c;聚焦于传统数据建模和数据…

catkin_make_workspace

ERROR1 : CMake Error at /opt/ros/melodic/share/cv_bridge/cmake/cv_bridgeConfig.cmake:113 (message): Project ‘cv_bridge’ specifies ‘/usr/include/opencv’ as an include dir, which is not found. It does neither exist as an absolute directory nor in ‘${{pr…

.net6 core web项目发布部署到Linux,以守护进程服务的形式部署启动,nginx实现转发

一、发布项目 1、以文件夹形式 2、目标运行时选对应的平台&#xff08;Linux-x64&#xff09; 3、文件夹选项&#xff1a;在发布前删除所有现有文件 二、部署项目&#xff08;安装.net6环境&#xff1a;参考Linux安装 dotnet sdk 6.0&#xff09; &#xff08;1&#xff09;…

网络基础,InetAddress,Socket,TCP,UDP

概念&#xff1a;两台设备之间通过网络实现数据运输网络通信&#xff1a;将数据通过网络从一台设备传输到另一台设备java.net包下提供了一系列的类或接口&#xff0c;供程序员使用&#xff0c;完成网络通信网络&#xff1a;两台或多台设备通过一定物理设备连接起来构成了网络根…

Scala中的Map 集合详解

目录 一、不可变长Map集合 1.map的声明与遍历 2.map的常用方法&#xff1a;get、getOrElse、keys、values、、&#xff1a; 二、可变长Map集合 三、Map的其他方法 key -> value 的语法形式实际上是用库中的隐式转换实现的&#xff0c;实际调用了 Map.apply 方法。Map.a…

盘点并发编程的12种业务场景,面试别再说你不会并发了

前言 并发编程是一项非常重要的技术&#xff0c;无论在面试&#xff0c;还是工作中出现的频率非常高。 并发编程说白了就是多线程编程&#xff0c;但多线程一定比单线程效率更高&#xff1f; 答&#xff1a;不一定&#xff0c;要看具体业务场景。 毕竟如果使用了多线程&…

力扣sql中等篇练习(十一)

力扣sql中等篇练习(十一) 1 好友申请|| :谁有最多的好友 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 出现数字次数越多,就代表它的好友越多 # 对两列数据合并时 不取出合并数据,采用UNION ALL SELECT t1.id,count(*) num FROM (SELECT request…

FreeRTOS - 计数信号量

一.任务功能 1、修改按键功能&#xff0c;模拟停车位出入功能 2、当按键按下 获取车位 3、当按键抬起 释放车位 二.API接口 函数原型SemaphoreHandle_t xSemaphoreCreateCounting( ①UBaseType_t uxMaxCount,②UBaseType_t uxInitialCount );功能概述创建计数信号量&#xff0c…

玩转ChatGPT:辅助编程

一、写在前面 首先让小Chat介绍自己在编程方面的天赋&#xff1a; 总结起来&#xff1a;TA掌握了海量的编程知识&#xff0c;能做到自动代码生成、代码审查优化、编程教学辅导以及实时问题解答。我问TA学习了多少案例&#xff0c;TA说&#xff1a;忘了&#xff0c;但保证够用。…

【Transformer系列(4)】Transformer模型结构超详细解读

前言 前一篇我们一起读了Transformer的论文《Attention Is All You Need》&#xff0c;不知道大家是否真的理解这个传说中的神&#xff08;反正俺是没有~&#xff09; 这两天我又看了一些视频讲解&#xff0c;感谢各位大佬的解读&#xff0c;让我通透了不少。 这篇文章就和…

语音交友app开发中的用户积分系统

引言 在当今数字时代&#xff0c;语音交友app已成为一种流行的社交工具。它们给用户提供了一个平台&#xff0c;在这里他们可以结交新朋友&#xff0c;分享他们的生活和信仰&#xff0c;并建立深厚的人际关系。然而&#xff0c;市场上存在大量的语音交友app&#xff0c;这使得…