在分布式集群中,对机器的添加、删除或者是机器故障后自动脱离集群等操作是分布式集群管理最基本的功能。如果采用的是常见的取模哈希算法,当有机器添加、删除之后,需要对数据做迁移,非常麻烦。
而一致性哈希利用哈希环的概念,保证增加或减少服务器,数据存储的改变最少,相比取模哈希算法大大节省了数据移动的开销,非常方便。
一致性哈希认为在动态变化的缓存空间环境中,良好的哈希算法应该满足以下几个方面:
一致性哈希可以理解成普通取模哈希算法的改良版,改变的是将普通的线性哈希空间变成环状的哈希空间,其中每一个缓存空间是环上的一个节点,数据一般存储在沿顺时针的方向找到的环上的第一个节点。
简单的说,一致性哈希是将整个哈希值空间想象成一个虚拟的圆环。
比如,假设哈希函数 H 的值空间为 0 ~ \(2^{32}-1\),整个哈希空间环如下:

假设这时有 k1、k2、k3、k4 这几个 key 值,通过一定的哈希算法,将这几个 key 值被平均分配到哈希环上。
同样的,现在有 3 台 cache 服务器,通过一定的哈希算法,也被平均分配到哈希环上。
下图展示的是 key 值被分配到哪一台 cache 服务器的一个示例:

如上所示:k1 存储在 c3 上,k4、k3 存储在 c1 上,k2 存储在 c2 上。
哈希环会将哈希后的 key 值按照顺时针的方向寻找最近的 cache 服务器,然后将数据存储在这台服务器上。
假设 c3 服务器宕机,这时候需要从集群中将其摘除,其上的数据也需要做迁移。
按照一致性哈希的规则,原本存储在 c3 上的 k1 按照顺时针的方向寻找最近的 cache 服务器,即后续 k1 会存储在 c1 上:

从这里可知,当使用一致性哈希时,删除节点 c3 会影响到被删除节点 c3 上及其下一个节点 c1 的数据,迁移数据的时候,需要将被删除节点 c3 上的数据迁移到其下一个节点 c1 上。
假设现在需要新增 c4 服务器,会破坏现在集群的平衡,需要对数据做一些处理。
假设 c4 服务器定位在 k4 和 k3 之间,按照一致性哈希的规则,原本存储在 c1 上的 k4 会迁移到 c4 上:

同样的,新增节点会影响到新增节点所在位置的后一个节点 c1,迁移数据的时候,需要将新增节点所在位置到其上一个节点 c3 之间的数据从其下一个节点 c1 迁移到新增的节点 c4 上。
一致性哈希理论上没有什么问题,但实际使用会存在以下问题:
这里就衍生出一个 虚拟节点 的概念,即对每个物理节点计算多个哈希值,将原来单一的物理节点在哈希环上虚拟出几个分身节点,这些分身节点称为虚拟节点。

映射到分身节点上的数据实际上就是映射到分身对应的物理节点上,这样一个物理节点可以通过虚拟节点的方式均匀分散在哈希环的各个部分,解决数据倾斜问题。
由于虚拟节点分散在哈希环各个部分,当某个节点宕机下线,虚拟节点所存储的数据会被均匀分配给下一个虚拟节点,则物理节点也会得到均匀分配,避免了对单一节点突发压力导致的节点雪崩问题。
在实际应用中,通常将虚拟节点数设置成 32 甚至更大,这样可以保证即使很少的服务节点也能做到均匀的数据分布。
一致性哈希算法相比普通的哈希算法在扩展性和容错性上都有一定的优势:
实际上,不会存在一劳永逸的哈希算法,一致性哈希算法在以下场景需要谨慎使用:
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
查看我的Ruby代码:h=Hash.new([])h[0]=:word1h[1]=h[1]输出是:Hash={0=>:word1,1=>[:word2,:word3],2=>[:word2,:word3]}我希望有Hash={0=>:word1,1=>[:word2],2=>[:word3]}为什么要附加第二个哈希元素(数组)?如何将新数组元素附加到第三个哈希元素? 最佳答案 如果您提供单个值作为Hash.new的参数(例如Hash.new([]),完全相同的对象将用作每个缺失键的默认值。这就是您所拥有的,那是你不想要的。您可以改用
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
假设我有一个在Ruby中看起来像这样的哈希:{:ie0=>"Hi",:ex0=>"Hey",:eg0=>"Howdy",:ie1=>"Hello",:ex1=>"Greetings",:eg1=>"Goodday"}有什么好的方法可以将它变成如下内容:{"0"=>{"ie"=>"Hi","ex"=>"Hey","eg"=>"Howdy"},"1"=>{"ie"=>"Hello","ex"=>"Greetings","eg"=>"Goodday"}} 最佳答案 您要求一个好的方法来做到这一点,所以答案是:一种您或同事可以在六个月后理解