一致性 hash

分布式过程中我们将服务分散到若干的节点上,以此通过集体的力量提升服务的目的。然而,对于一个客户端来说,该由哪个节点服务呢?或者说对某个节点来说他分配到哪些任务呢?

强哈希

考虑到单服务器不能承载,因此使用了分布式架构,最初的算法为 hash() mod n, hash()通常取用户ID,n为节点数。此方法容易实现且能够满足运营要求。缺点是当单点发生故障时,系统无法自动恢复。同样不也不能进行动态增加节点。

弱哈希

为了解决单点故障,使用 hash() mod (n/m),

这样任意一个用户都有 m 个服务器备选,可由 client 随机选取。

由于不同服务器之间的用户需要彼此交互,所以所有的服务器需要确切的知道用户所在的位置。

因此用户位置被保存到 memcached 中。当一台发生故障,client 可以自动切换到对应 backup,由于切换前另外 1 台没有用户的 session,因此需要 client 自行重新登录。

  • 好处

他比强哈希的好处是:解决了单点问题。

  • 缺点

但存在以下问题:负载不均衡,尤其是单台发生故障后剩下一台会压力过大;不能动态增删节点;节点发生故障时需要 client 重新登录

一致性 hash 算法

一致性 hash 算法提出了在动态变化的 Cache 环境中,判定哈希算法好坏的四个定义:

平衡性(Balance)

平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。

单调性(Monotonicity)

单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。

分散性(Spread)

在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。

当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。

这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。

负载(Load)

负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。

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

普通的哈希算法(也称硬哈希)采用简单取模的方式,将机器进行散列,这在cache环境不变的情况下能取得让人满意的结果,但是当cache环境动态变化时,
这种静态取模的方式显然就不满足单调性的要求(当增加或减少一台机子时,几乎所有的存储内容都要被重新散列到别的缓冲区中)。

代码实现

实现逻辑

一致性哈希算法有多种具体的实现,包括 Chord 算法KAD 算法等实现,以上的算法的实现都比较复杂。

这里介绍一种网上广为流传的一致性哈希算法的基本实现原理,感兴趣的同学可以根据上面的链接或者去网上查询更详细的资料。

一致性哈希算法的基本实现原理是将机器节点和key值都按照一样的hash算法映射到一个0~2^32的圆环上。

当有一个写入缓存的请求到来时,计算 Key 值 k 对应的哈希值 Hash(k),如果该值正好对应之前某个机器节点的 Hash 值,则直接写入该机器节点,
如果没有对应的机器节点,则顺时针查找下一个节点,进行写入,如果超过 2^32 还没找到对应节点,则从0开始查找(因为是环状结构)。

如图 1 所示:

图 1 中 Key K 的哈希值在 A 与 B 之间,于是 K 就由节点B来处理。

另外具体机器映射时,还可以根据处理能力不同,将一个实体节点映射到多个虚拟节点。

经过一致性哈希算法散列之后,当有新的机器加入时,将只影响一台机器的存储情况,

例如新加入的节点H的散列在 B 与 C 之间,则原先由 C 处理的一些数据可能将移至 H 处理,
而其他所有节点的处理情况都将保持不变,因此表现出很好的单调性。

而如果删除一台机器,例如删除 C 节点,此时原来由 C 处理的数据将移至 D 节点,而其它节点的处理情况仍然不变。

而由于在机器节点散列和缓冲内容散列时都采用了同一种散列算法,因此也很好得降低了分散性和负载。

而通过引入虚拟节点的方式,也大大提高了平衡性。

实现代码

consitent-hashing

原文地址

consitent-hashing

强一致性hash实现java版本及强一致性hash原理的更多相关文章

  1. at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)

    at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333) 原因: null request

  2. Java 集合 散列表hash table

    Java 集合 散列表hash table @author ixenos 摘要:hash table用链表数组实现.解决散列表的冲突:开放地址法 和 链地址法(冲突链表方式) hash table 是 ...

  3. 【转】Java计算文件的hash值

    原文地址:http://blog.csdn.net/qq_25646191/article/details/78863110 如何知道一个文件是否改变了呢?当然是用比较文件hash值的方法,文件has ...

  4. Java中String的hash函数分析

    转载自:http://blog.csdn.net/hengyunabc/article/details/7198533 JDK6的源码: [java] view plaincopy /** * Ret ...

  5. JAVA版本区块链钱包核心代码

    Block.java package com.ppblock.blockchain.core; import java.io.Serializable; /** * 区块 * @author yang ...

  6. Java版本:识别Json字符串并分隔成Map集合

    前言: 最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本. 过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案. 遇到的C#转Java的一些 ...

  7. 你的程序支持复杂的时间调度嘛?如约而来的 java 版本

    你的程序支持复杂的时间调度嘛? 这篇文章介绍了时间适配器的c#版本,是给客户端用的,服务器自然也要有一套对应的做法,java版本的 [年][月][日][星期][时间] [*][*][*][*][*] ...

  8. 崔用志-微信开发-java版本

    崔用志-微信开发-java版本 今天看到一些关于微信开发的知识蛮好的博客,分享给大家,希望对大家有帮助. 微信开发准备(一)--Maven仓库管理新建WEB项目 微信开发准备(二)--springmv ...

  9. java版本区别

    java版本区别 点我,点我,Eclipse几个版本号的区别(part1) 点我,点我,Eclipse几个版本号的区别(part2) 点我,点我,Eclipse几个版本号的区别(part3)

随机推荐

  1. seriviceWorker 小结

    serviceWorker 的状态 install → activate. 1.初进页面,此前未加载过serviceWorker,直接进入install状态,随后进入activate状态,但是此时se ...

  2. 转发: 探秘Java中的String、StringBuilder以及StringBuffer

    原文地址 探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家 ...

  3. 我的代码-statistic analysis

    # coding: utf-8 # In[1]: # numpy and pandas for data manipulationimport numpy as npimport pandas as ...

  4. js中的call与apply随笔

    关于javascript中的call方法.总结网上的观点: 1: 继承. 2: 修改函数运行时的this指针. 可能说起来还是比较抽象,下面具体例子说一下: x.call(y) (1)y.m = x  ...

  5. python之 类对象 类方法 实例对象 实例方法 静态方法

    实例对象1. 创建的时间:使用 类名()的时候,就创建一个实例对象2. 实例属性:怎样添加 只要是一个变量能够指向这个实例对象,那么这个变量.xxxx = 111就是给其添加一个实例属性 特点: 跟着 ...

  6. [Java Web学习]Spring MVC使用普通类对象,声明的对象为null

    由于对Spring还不熟悉,目前还处于学习阶段,因此经常会遇到一些小白问题,这个问题需要在Spring文件中将普通对象注入bean,然后在MVC中添加set方法,填充普通对象.

  7. Linux下安装gradle

    Linux下安装gradle 1. Gradle 是以 Groovy 语言为基础,面向Java应用为主.基于DSL(领域特定语言)语法的自动化构建工具 下面就描述一下如何在linux环境下安装配置gr ...

  8. C++插入排序

    直接插入排序是一种简单的插入排序法,适用于少量数据的排序,是一种较为稳定的排序算法,本文通过插入排序的方法实现对一个数组进行从大到小和从小到大的排序. 1. 从小到大的插入排序: 例如:给定整型数组a ...

  9. eclipse与visualVM与mat

    GC与CPU与内存的查看与分析 本文主要讲visualVM,MAT的下载配置;以及如何运用visualVM生成hprof文件;如何用visualVM分析CPU消耗,程序瓶颈在哪里;怎么用MAT导入hp ...

  10. Acrobat.CAcroPDDoc open 无法找到指定文件

    pdfDoc = (Acrobat.CAcroPDDoc)Microsoft.VisualBasic.Interaction.CreateObject("AcroExch.PDDoc&quo ...