一致性哈希算法以及其PHP实现详细解析


Posted in PHP onAugust 24, 2013

在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括:  轮循算法(Round Robin)、哈希算法(HASH)、最少连接算法(Least Connection)、响应速度算法(Response Time)、加权法(Weighted )等。其中哈希算法是最为常用的算法.

典型的应用场景是: 有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分发到每台服务器上,每台机器负责1/N的服务。

常用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,按照自定义的hash()算法,对每个请求的hash()值按N取模,得到余数i,然后将请求分发到编号为i的机器。但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;如果新增一台机器,会有N /(N+1)的服务器的缓存数据需要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。那么,如何设计一个负载均衡策略,使得受到影响的请求尽可能的少呢?

在Memcached、Key-Value Store、Bittorrent DHT、LVS中都采用了Consistent Hashing算法,可以说Consistent Hashing 是分布式系统负载均衡的首选算法。

1、Consistent Hashing算法描述

下面以Memcached中的Consisten Hashing算法为例说明。
由于hash算法结果一般为unsigned int型,因此对于hash函数的结果应该均匀分布在[0,232-1]间,如果我们把一个圆环用232 个点来进行均匀切割,首先按照hash(key)函数算出服务器(节点)的哈希值, 并将其分布到0~232的圆上。

用同样的hash(key)函数求出需要存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器(节点)上。

一致性哈希算法以及其PHP实现详细解析 Consistent Hashing原理示意图

新增一个节点的时候,只有在圆环上新增节点逆时针方向的第一个节点的数据会受到影响。删除一个节点的时候,只有在圆环上原来删除节点顺时针方向的第一个节点的数据会受到影响,因此通过Consistent Hashing很好地解决了负载均衡中由于新增节点、删除节点引起的hash值颠簸问题。

一致性哈希算法以及其PHP实现详细解析 Consistent Hashing添加服务器示意图

虚拟节点(virtual nodes):之所以要引进虚拟节点是因为在服务器(节点)数较少的情况下(例如只有3台服务器),通过hash(key)算出节点的哈希值在圆环上并不是均匀分布的(稀疏的),仍然会出现各节点负载不均衡的问题。虚拟节点可以认为是实际节点的复制品(replicas),本质上与实际节点实际上是一样的(key并不相同)。引入虚拟节点后,通过将每个实际的服务器(节点)数按照一定的比例(例如200倍)扩大后并计算其hash(key)值以均匀分布到圆环上。在进行负载均衡时候,落到虚拟节点的哈希值实际就落到了实际的节点上。由于所有的实际节点是按照相同的比例复制成虚拟节点的,因此解决了节点数较少的情况下哈希值在圆环上均匀分布的问题。

一致性哈希算法以及其PHP实现详细解析 

虚拟节点对Consistent Hashing结果的影响

从上图可以看出,在节点数为10个的情况下,每个实际节点的虚拟节点数为实际节点的100-200倍的时候,结果还是很均衡的。

第3段中有这些文字:“但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;”

为何是 (N-1)/N 呢?解释如下:

比如有 3 台机器,hash值 1-6 在这3台上的分布就是:
host 1: 1 4
host 2: 2 5
host 3: 3 6
如果挂掉一台,只剩两台,模数取 2 ,那么分布情况就变成:
host 1: 1 3 5
host 2: 2 4 6

可以看到,还在数据位置不变的只有2个: 1,2,位置发生改变的有4个,占共6个数据的比率是 4/6 = 2/3这样的话,受影响的数据太多了,势必太多的数据需要重新从 DB 加载到 cache 中,严重影响性能

【consistent hashing 的办法】
上面提到的 hash 取模,模数取的比较小,一般是负载的数量,而 consistent hashing 的本质是将模数取的比较大,为 2的32次方减1,即一个最大的 32 位整数。然后,就可以从容的安排数据导向了,那个图还是挺直观的。
以下部分为一致性哈希算法的一种PHP实现。点击下载

PHP 相关文章推荐
判“新”函数:得到今天与明天的秒数
Oct 09 PHP
PHP中的错误处理、异常处理机制分析
May 07 PHP
探讨:parse url解析URL,返回其组成部分
Jun 14 PHP
php中的strpos使用示例
Feb 27 PHP
PHP入门经历和学习过程分享
Apr 11 PHP
php强制运行广告的方法
Dec 01 PHP
PHP读取PPT文件的方法
Dec 10 PHP
PHP实现查询两个数组中不同元素的方法
Feb 23 PHP
Yii2针对游客、用户防范规则和限制的解决方法分析
Oct 08 PHP
[原创]php集成安装包wampserver修改密码后phpmyadmin无法登陆的解决方法
Nov 23 PHP
php制作基于xml的RSS订阅源功能示例
Feb 08 PHP
PHP 进度条函数的简单实例
Sep 19 PHP
PHP如何利用P3P实现跨域
Aug 24 #PHP
PHP引用符&的用法详细解析
Aug 22 #PHP
新手菜鸟必读:session与cookie的区别
Aug 22 #PHP
PHP mysql与mysqli事务使用说明 分享
Aug 17 #PHP
php中url传递中文字符,特殊危险字符的解决方法
Aug 17 #PHP
测试PHP连接MYSQL成功与否的代码
Aug 16 #PHP
PHP 通过Socket收发十六进制数据的实现代码
Aug 16 #PHP
You might like
smarty表格换行实例
2014/12/15 PHP
功能强大的PHP POST提交数据类
2016/07/15 PHP
PHP实现合并两个排序链表的方法
2018/01/19 PHP
Javascript学习笔记5 类和对象
2010/01/11 Javascript
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
window.addEventListener来解决让一个js事件执行多个函数
2012/12/26 Javascript
jquery中通过父级查找进行定位示例
2013/06/28 Javascript
jQuery 遍历函数详解
2015/07/05 Javascript
javacript获取当前屏幕大小
2016/06/04 Javascript
老生常谈 关于JavaScript的类的继承
2016/06/24 Javascript
js内置对象处理_打印学生成绩单的简单实现
2016/09/24 Javascript
JavaScript中Math对象的方法介绍
2017/01/05 Javascript
Vue实现点击后文字变色切换方法
2018/02/11 Javascript
详解Vue单元测试case写法
2018/05/24 Javascript
Vue 与 Vuex 的第一次接触遇到的坑
2018/08/16 Javascript
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
2019/10/16 jQuery
Element-UI+Vue模式使用总结
2020/01/02 Javascript
[56:56]VG vs LGD 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.22
2019/09/05 DOTA
python递归计算N!的方法
2015/05/05 Python
python tensorflow学习之识别单张图片的实现的示例
2018/02/09 Python
用python与文件进行交互的方法
2018/03/01 Python
Python判断两个list是否是父子集关系的实例
2018/05/04 Python
python远程连接服务器MySQL数据库
2018/07/02 Python
Python匿名函数及应用示例
2019/04/09 Python
pycharm 批量修改变量名称的方法
2019/08/01 Python
浅谈Python 参数与变量
2020/06/20 Python
Django --Xadmin 判断登录者身份实例
2020/07/03 Python
CSS3 text shadow字体阴影效果
2016/01/08 HTML / CSS
经济实惠的名牌太阳镜和眼镜:Privé Revaux
2021/02/07 全球购物
现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset
2012/11/09 面试题
内科护士实习自我鉴定
2013/10/17 职场文书
个人简历自荐信
2013/12/05 职场文书
公司前台辞职报告
2014/01/19 职场文书
JavaScript利用html5新方法操作元素类名详解
2021/11/27 Javascript
yyds什么意思?90后已经听不懂00后讲话了……
2022/02/03 杂记