`

一致性哈希环(转)

 
阅读更多

http://blog.codinglabs.org/articles/consistent-hashing.html

摘要

本文将会从实际应用场景出发,介绍一致性哈希算法(Consistent Hashing)及其在分布式系统中的应用。首先本文会描述一个在日常开发中经常会遇到的问题场景,借此介绍一致性哈希算法以及这个算法如何解决此问题;接下来会对这个算法进行相对详细的描述,并讨论一些如虚拟节点等与此算法应用相关的话题。

分布式缓存问题

假设我们有一个网站,最近发现随着流量增加,服务器压力越来越大,之前直接读写数据库的方式不太给力了,于是我们想引入Memcached作为缓存机制。现在我们一共有三台机器可以作为Memcached服务器,如下图所示。

很显然,最简单的策略是将每一次Memcached请求随机发送到一台Memcached服务器,但是这种策略可能会带来两个问题:一是同一份数据可能被存在不同的机器上而造成数据冗余,二是有可能某数据已经被缓存但是访问却没有命中,因为无法保证对相同key的所有访问都被发送到相同的服务器。因此,随机策略无论是时间效率还是空间效率都非常不好。

要解决上述问题只需做到如下一点:保证对相同key的访问会被发送到相同的服务器。很多方法可以实现这一点,最常用的方法是计算哈希。例如对于每次访问,可以按如下算法计算其哈希值:

h = Hash(key) % 3

其中Hash是一个从字符串到正整数的哈希映射函数。这样,如果我们将Memcached Server分别编号为0、1、2,那么就可以根据上式和key计算出服务器编号h,然后去访问。

这个方法虽然解决了上面提到的两个问题,但是存在一些其它的问题。如果将上述方法抽象,可以认为通过:

h = Hash(key) % N

这个算式计算每个key的请求应该被发送到哪台服务器,其中N为服务器的台数,并且服务器按照0 – (N-1)编号。

这个算法的问题在于容错性和扩展性不好。所谓容错性是指当系统中某一个或几个服务器变得不可用时,整个系统是否可以正确高效运行;而扩展性是指当加入新的服务器后,整个系统是否可以正确高效运行。

现假设有一台服务器宕机了,那么为了填补空缺,要将宕机的服务器从编号列表中移除,后面的服务器按顺序前移一位并将其编号值减一,此时每个key就要按h = Hash(key) % (N-1)重新计算;同样,如果新增了一台服务器,虽然原有服务器编号不用改变,但是要按h = Hash(key) % (N+1)重新计算哈希值。因此系统中一旦有服务器变更,大量的key会被重定位到不同的服务器从而造成大量的缓存不命中。而这种情况在分布式系统中是非常糟糕的。

一个设计良好的分布式哈希方案应该具有良好的单调性,即服务节点的增减不会造成大量哈希重定位。一致性哈希算法就是这样一种哈希方案。

一致性哈希算法

算法简述

一致性哈希算法(Consistent Hashing)最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。简单来说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0 - 232-1(即哈希值是一个32位无符号整形),整个哈希空间环如下:

整个空间按顺时针方向组织。0和232-1在零点中方向重合。

下一步将各个服务器使用H进行一个哈希,具体可以选择服务器的ip或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置,这里假设将上文中三台服务器使用ip地址哈希后在环空间的位置如下:

接下来使用如下算法定位数据访问到相应服务器:将数据key使用相同的函数H计算出哈希值h,通根据h确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。

例如我们有A、B、C、D四个数据对象,经过哈希计算后,在环空间上的位置如下:

根据一致性哈希算法,数据A会被定为到Server 1上,D被定为到Server 3上,而B、C分别被定为到Server 2上。

容错性与可扩展性分析

下面分析一致性哈希算法的容错性和可扩展性。现假设Server 3宕机了:

可以看到此时A、C、B不会受到影响,只有D节点被重定位到Server 2。一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。

下面考虑另外一种情况,如果我们在系统中增加一台服务器Memcached Server 4:

此时A、D、C不受影响,只有B需要重定位到新的Server 4。一般的,在一致性哈希算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。

综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

虚拟节点

一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如我们的系统中有两台服务器,其环分布如下:

此时必然造成大量数据集中到Server 1上,而只有极少量会定位到Server 2上。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况,我们决定为每台服务器计算三个虚拟节点,于是可以分别计算“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”、“Memcached Server 2#1”、“Memcached Server 2#2”、“Memcached Server 2#3”的哈希值,于是形成六个虚拟节点:

同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”三个虚拟节点的数据均定位到Server 1上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

总结

目前一致性哈希基本成为了分布式系统组件的标准配置,例如Memcached的各种客户端都提供内置的一致性哈希支持。本文只是简要介绍了这个算法,更深入的内容可以参看论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》,同时提供一个C语言版本的实现供参考。

分享到:
评论

相关推荐

    一致性哈希与Chord1

    引入虚拟节点,可以有效地防止物理节点(机器)映射到哈希环中出现不均匀的情况。比如上图中的机器 A、B、C 都映射在环的右半边上。一般,虚拟节点会比物理节点多很多

    hash_ring:水晶一致性哈希环的实现

    hash_ring 当操作分布式服务器时,“一致性哈希环”是一个有用的数据结构。 该库是基于出色的实现的Consistent Hash Ring的实现。安装将此添加到应用程序的shard.yml : dependencies : hash_ring : github : ...

    scurry:leveldbs的一致哈希环

    疾走一个由leveldb支持的一致性哈希环,可满足您的缓存需求。 我可以看到有一天您可能希望将数据放入其中,并且有一定的信心,您可能会再次将其取回。 如果这使您感到恐惧,那应该是。各一份罗德Vagg的节点+性...

    uhashring:与ketama兼容的全功能一致哈希Python库

    在现实世界的应用程序中使用许多一致的哈希环的便捷方法。 通过猴子补丁与其他库(例如内存缓存)的简单集成。 如果需要使用,则具有完全的兼容性(请参阅下面的重要说明)。 对于ketama用户,libketama C ...

    ist的matlab代码-hash_ring:在Python中实现一致的哈希(使用md5作为哈希函数)

    一致性哈希是一种以提供或删除一个插槽不会显着改变键到插槽的映射的方式提供哈希表功能的方案。 可以在博客文章中阅读有关hash_ring的更多信息(该文章更详细地解释了该想法): 一致的散列仅在python中实现 这些...

    Ketama一致性Hash算法(含Java代码) 1

    如果没有找到,则取整个环的第个节点。测试结果测试代码是整理的,主体法没有变分布平均性测试:测试随机成的众多key是否会平均分布到各个结点上测试结果如下:最上是参

    websocket-cluster:这是一个针对WebSocket集群服务器的Spring Cloud项目。

    原理我们利用一致性哈希算法,构造一个哈希环,网关监听WebSocket服务实例的上下线消息,根据实例的变化动态地更新哈希环。将需要迁移的WebSocket客户端重新连接到新的实例上,这样的代价是最小的;当然也取决与虚拟...

    consistent-hash-js:JavaScript中的一致哈希

    一致性哈希 这是环的一种无依赖Java的实现。 使用字符串作为哈希键,并使用PJW哈希变体哈希。 该实现非常快,并且具有良好的密钥分发。 var ConsistentHash = require('consistent-hash') var hr = new ...

    consistent-hash:一致的哈希追踪器项目符号

    环一致散列跳转一致哈希集合一致哈希磁悬浮一致性哈希 (第3.4节)粗略设计注意事项从与Karger等人成一直线的圆圈开始N个节点可以复制R次以改善分片分布。 复制的节点称为虚拟节点。 分片复制节点的散列在cicle上成...

    Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving

    第一次提出一致性哈希环的论文,说的是比较好的,稍微有点英语基础的,应该都可以看懂。在分布式,缓存流行的今天,确实是不错的充电利器。

    一致性hash算法1

    2.每一个缓存key都可以通过Hash算法转化为一个32位的二进制数,也就对应着环形空间的某一个缓存区 3.我们的每一个缓存节点(Shard)也遵循同样的Has

    Distributed-Editing:使用Chord DHT(分布式哈希表)的对等并发富文本编辑平台

    扩展的分布式操作转换算法可确保在分布式节点中同时更新副本的一致性。 重要文件: main.py:索引服务器仅使用一个IP维护所有打开的文档的列表,新节点进入处理文档的对等网络需要使用一个IP。 Notepad.py:此...

    Doss:去分布式对象存储

    根据标准的一致性哈希算法实现了hashRing,并加入数据服务器存储空间大小不同等权重来平衡各节点的虚拟多维数据集复制因子,对象读取请求均根据对象名进行哈希运算映射到虚拟多维数据集上,再由虚拟多维数据集映射到...

    matlab代码做游戏-awesome-crystal:https://github.com/veelenga/awesome-crystal

    -一致性哈希环的实现 -建立马尔可夫链并运行马尔可夫过程 -实现算法以检查数字是否为质数 -实施多套 -Cassandra使用的Murmur3哈希算法的实现 -灵活的Radix Tree实现 -基数树的实现 -三元搜索树 -文本算法的集合 Api...

    海量数据去重的Hash与BloomFilter,bitmap1

    背景分布式一致性 hash 算法将哈希空间组织成一个虚拟的圆环,圆环的大小是,最终会得到一个 [0,] 之间的一个无符号整型,这个整数代表服务器的编号;多个服务

    matlab说话代码-awesome-crystal:很棒的Crystal库,工具,框架和软件的集合

    -一致性哈希环的实现 -Haversine公式的实现 -“ K维树”和“ N最近邻居”的实现 -K稳定的全球唯一ID -建立马尔可夫链并运行马尔可夫过程 -实施多套 -灵活的Radix Tree实现 -基数树实施 -三元搜索树 Api建筑商 -使用...

    grain:在分散的环境中以足够快速,有效且容错的方式协调您的分布式服务

    为了避免出现集中式角色,我们采用游泳成员协议,从分配一致的哈希环,进行分散的元信息跟踪和决策,包括任务分配,扩展和负载平衡。 组成的IoT设备没有单点故障,在群集设置中封装了不稳定的成员可见性和零痛配置...

    乐视秒杀:每秒十万笔交易的数据架构解读

    在redis,memcached等缓存系统盛行的互联网时代,构建一个支撑每秒十万只读的系统并不复杂,无非是通过一致性哈希扩展缓存节点,水平扩展web服务器等。支付系统要处理每秒十万笔订单,需要的是每秒数十万的数据库...

    每秒处理10万订单乐视集团支付架构

    在redis,memcached等缓存系统盛行的互联网时代,构建一个支撑每秒十万只读的系统并不复杂,无非是通过一致性哈希扩展缓存节点,水平扩展web服务器等。支付系统要处理每秒十万笔订单,需要的是每秒数十万的数据库...

Global site tag (gtag.js) - Google Analytics