分布式一致性hash算法简介

当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么。在分析分布式一致性hash算法原理之前,我们先来了解一下这几个概念。

分布式

分布式(distributed)是指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作,对外提供服务。

以一个航班订票系统为例,这个航班订票系统有航班预定、网上值机、旅客信息管理、订单管理、运价计算等服务模块。现在要以集中式(集群,cluster分布式的方式进行部署,下面我们来看看它们部署的示意图。

集中式示部署意图

图 分布式部署示意图

从上面的集中式示部署意图和分布式部署示意图中我们可以看出,集中式将一个系统的所有服务模块部署到了不同的服务器上,构成一个集群,通过负载均衡设备对外提供服务。分布式则将不同的服务模块分布在不同的服务器上

从上图我们也可以看出,分布式部署方案中,不仅仅是分布式服务,还有分布式数据存储分布式静态资源分布式计算等。此时,可能你已经回忆起上提到的,memcached不就是一套分布式的缓存系统吗。对,没错,memcached的分布式就体现在分布式数据存储,“分布式一致性hash算法”中的“分布式”就是指缓存数据的分布性。

一致性

了解了分布式之后,一致性就好理解了。有分布式数据存储数据,那就离不开分布式提取数据。一致性即存储数据到memcached和从memcached中提取数据的时候采用的算法要一致以保持数据一致性。即当以hash算法将数据存储到memcached时,提取该数据时,也要以hash算法进行提取。

Hash

hash,俗称“哈希”,也叫散列,是一种将任意长度的消息(数据)压缩到某一固定长度的消息摘要(数据)的算法。常见的hash算法有MD5,SHA等。hash算法具有两个重要的特性:不可逆性(即从hash值反推出原消息是不可能的)、抗冲突性(即给定消息M1,不存在另一个消息M2,使得Hash(M1)=Hash(M2))和分布均匀性(即hash的结果是均匀分布的)。memcached中,存取数据时都要进行哈希映射。正是这两个特性,保证了memcached缓存中key值得唯一性。

图 消息哈希过程示意图

三个词已经介绍完了,那memcached为什么要使用分布式一致性hash算法呢,继续看下文。

分布式一致性hash算法使用背景

我们已经知道,memcached的分布式主要在于客户端的分布式算法。memcached客户端就像一个网络中的路由,经过特定的算法将数据分散的存在到memcached服务端的机器上,又从分散的memcached服务端的机器上提取数据。实际中,常见的存储和提取数据的算法有取模算法和本文分析的一致性hash算法。

取模算法算法的原理是:

hash(key)%N

其中key 代表数据的键,N代表memcached服务器的数量。取模的结果就是memcached客户端要定位的memcached服务器。取模算法很明显,结果很容易受N的影响,当服务器数量N增加或者减少的时候,原先的缓存数据定位几乎失效,缓存数据定位失效意味着要到数据库重新查询,这对于高并发的系统来说是致命的。于是,人们提出了一致性hash算法最终目的是实现在移除、添加一个memcached服务器时对已经存在的缓存数据的定位影响尽可能的降到最小

分布式一致性hash算法的简介和使用背景已经介绍完了,想必你对“分布式一致性hash算法”这个词已经不陌生了,下面将开启我们的”分布式一致性hash算法”原理的讲解。

环形hash空间

通常,一个缓存数据的key经过hash后会得到一个32位的值,也就是0~2^32 - 1数值范围。我们可以把这个数值范围抽象成一个首尾相连环形的空间,我们称这个空间为环形hash空间。如下图所示:

图 环形hash空间

映射key到环形hash空间

有了环形hash空间之后,缓存数据的key经过hash后得到的值就映射到了环形hash空间。假设有key1、key2、key3、key4,经过hash后,映射到环形hash空间如下图所示:

图 key映射到环形hash空间

映射server节点到hash空间

同理,我们可以把memcached服务器抽象成网络上的节点经过hash后映射到环形hash空间。假设有server1、server2、server3,经过hash后,映射到环形hash空间如下图所示:

图 server节点映射到环形hash空间

映射key到server节点

现在缓存key和server节点都经过一致性hash算法映射到了环形hash空间,现在就可以将缓存key和server节点的关系进行映射了。顺时针沿着环形hash空间,从某个缓存key开始,直到遇到一个server节点,那么该缓存key就存储到这个server节点上。如图:

图 key映射到server节点

了解了key、server节点、hash空间之间的映射关系之后,现在我们已经清楚了缓存数据是怎样分布的存储到memcached服务器了。查找缓存数据的时候,也采用同样的映射方法来定位。

添加server节点

现在我们已经知道memcached存储和访问数据的策略了。那么当在server集群中增加一个server节点时,对数据访问的命中率又有什么影响呢。如下图,我在serverC和serverD节点之间增加一个节点serverF。

图 增加serverF节点

从上图可以看出,增加serverF节点后,原有的缓存数据分布中,仅有serverC~serverF节点的数据进行了重新分布,这部分数据需要重新到数据库查找再次映射到新添加的serverF节点上。尽管不能命中的缓存数据仍然存在,但相对于取模算法,已经是最大限度地抑制了hash键的重新分布。

删除server节点

同理,当在server集群中删除serverC节点时,受影响的也仅是serverB~serverC之间的缓存数据,这部分数据需要重新到数据库查找再次映射到serverD节点上。如下图所示:

图 删除serverC节点

虚拟节点的引入

我们已经知道,添加和删除节点都会影响缓存数据的分布。尽管hash算法具有分布均匀的特性,但是当集群中server数量很少时,他们可能在环中的分布并不是特别均匀,进而导致缓存数据不能均匀分布到所有的server上。为解决这个问题,需要使用虚拟节点的思想:为每个物理节点(server)在环上分配100~200个点,这样环上的节点较多,就能抑制分布不均匀。当为cache定位目标server时,如果定位到虚拟节点上,就表示cache真正的存储位置是在该虚拟节点代表的实际物理server上。如下图所示:

图 引入虚拟server节点

另外,如果每个实际server节点的负载能力不同,可以赋予不同的权重,根据权重分配不同数量的虚拟节点。

虚拟节点的hash计算可以采用对应节点的 IP 地址加数字后缀的方式。例如假设 serverA 的 IP 地址为 127.0.0.1 。引入虚拟节点前,计算serverA 的 hash 值:

hash(“127.0.0.1”);

和 serverA12 的 hash 值:hash(“127.0.0.1#1”);

hash(“127.0.0.1#2”);

节点变化数据分流的问题

上面讨论的节点变化都会导致部分缓存数据的重新分布,hash算法还有一个重要的衡量指标:hash算法的结果能够保证需要重新分布的缓存数据能映射到新的server节点中。

一致性hash算法与取模算法的比较

取模算法的方法简单,数据的分散性也可以,但其主要缺点是当添加或移除server节点时,缓存重新映射的代价相当巨大。添加或移除server节点时,余数就会产生巨变,这样就无法定位与存储时相同的server节点,从而影响缓存的命中率。而一致性hash算法则最大限度的减少了server节点变化带来的影响,当节点变化时,只影响一个server节点的部分数据,且hash算法能够保证需要重新分布的缓存数据能映射到新的server节点中。

参考文档

http://blog.csdn.net/sparkliang/article/details/5279393

http://www.blogjava.net/hao446tian/archive/2013/01/29/394858.html

http://www.dexcoder.com/selfly/article/2388

http://www.cnblogs.com/lintong/p/4383427.html

http://blog.csdn.net/fdipzone/article/details/7170045

http://blog.jobbole.com/95588/

分布式缓存技术memcached学习(四)—— 一致性hash算法原理的更多相关文章

  1. 分布式缓存技术memcached学习系列(四)—— 一致性hash算法原理

    分布式一致性hash算法简介 当你看到"分布式一致性hash算法"这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前, ...

  2. 分布式缓存技术memcached学习(五)—— memcached java客户端的使用

    Memcached的客户端简介 我们已经知道,memcached是一套分布式的缓存系统,memcached的服务端只是缓存数据的地方,并不能实现分布式,而memcached的客户端才是实现分布式的地方 ...

  3. 分布式缓存技术memcached学习系列(五)—— memcached java客户端的使用

    Memcached的客户端简介 我们已经知道,memcached是一套分布式的缓存系统,memcached的服务端只是缓存数据的地方,并不能实现分布式,而memcached的客户端才是实现分布式的地方 ...

  4. 分布式缓存技术memcached学习(二)——memcached基础命令

    上文<linux环境下编译memcahed>介绍了memcahed在linux环境下的安装以及登录,下面介绍memcahed的基本命令的使用. Add 功能:往内存增加一条新的缓存记录 语 ...

  5. 分布式缓存技术memcached学习系列(二)——memcached基础命令

    上文<linux环境下编译memcahed>介绍了memcahed在linux环境下的安装以及登录,下面介绍memcahed的基本命令的使用. Add 功能:往内存增加一条新的缓存记录 语 ...

  6. 分布式缓存技术memcached学习(三)——memcached内存管理机制

    几个重要概念 Slab memcached通过slab机制进行内存的分配和回收,slab是一个内存块,它是memcached一次申请内存的最小单位,.在启动memcached的时候一般会使用参数-m指 ...

  7. 分布式缓存技术memcached学习系列(三)——memcached内存管理机制

    几个重要概念 Slab memcached通过slab机制进行内存的分配和回收,slab是一个内存块,它是memcached一次申请内存的最小单位,.在启动memcached的时候一般会使用参数-m指 ...

  8. 分布式缓存技术memcached学习(一)——linux环境下编译memcahed

    安装依赖工具 [root@localhost upload]# yum  install gcc  make  cmake  autoconf  libtool 下载并上传文件 memcached 依 ...

  9. 分布式缓存技术memcached学习系列(一)——linux环境下编译memcahed

    安装依赖工具 [root@localhost upload]# yum  install gcc  make  cmake  autoconf  libtool 下载并上传文件 memcached 依 ...

随机推荐

  1. [UOJ30/Codeforces Round #278 E]Tourists

    传送门 好毒瘤的一道题QAQ,搞了好几好几天. UOJ上卡在了53个点,CF上过了,懒得优化常数了 刚看时一眼Tarjan搞个强连通分量然后缩点树链剖分xjb搞搞就行了,然后写完了,然后WA了QAQ. ...

  2. PostgreSQL Apt Repository

    PostgreSQL Apt Repository If the version included in your version of Ubuntu is not the one you want, ...

  3. easyUi 框架中的JS文件传递参数的区别

    1.情景一 //JS文件 ajax的请求url : parent.baseUrl+"user/customer/findOne/" + id, //后台JAVA代码接收参数 @Re ...

  4. Mysql 该如何 Entity Framework 数据库迁移 和 如何更好的支持EntityFramework.Extended

    问题 1.在使用EntityFramework访问Mysql的时候,使用迁移来生成数据库或者更新数据库时候会遇到一些问题 2.EntityFramework.Extended对Mysql的支持不是很完 ...

  5. Android 四大组件之Service

    ---恢复内容开始--- 1,Service的生命周期

  6. js闭包的作用域以及闭包案列的介绍:

    转载▼ 标签: it   js闭包的作用域以及闭包案列的介绍:   首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...

  7. linux下共享库的注意点之-fpic

    在编译共享库必须加上-fpic.这是为什么呢? 首先看一个简单的例子: #include <stdio.h> int fun1() { printf("fun1\n") ...

  8. GenomicRangeQuery /codility/ preFix sums

    首先上题目: A DNA sequence can be represented as a string consisting of the letters A, C, G and T, which ...

  9. Linux C 字符串函数 sprintf()、snprintf() 详解

    一.sprintf() 函数详解 在将各种类 型的数据构造成字符串时,sprintf 的强大功能很少会让你失望. 由于 sprintf 跟 printf 在用法上几乎一样,只是打印的目的地不同而已,前 ...

  10. sql 创建表、删除表 增加字段 删除字段操作

    下面是Sql Server 和 Access 操作数据库结构的常用Sql,希望对你有所帮助. 新建表:create table [表名]([自动编号字段] int IDENTITY (1,1) PRI ...