最近在看一些分布式方面的文章,所以就用php实现一致性hash来练练手,以前一般用的是最原始的hash取模做分布式,当生产过程中添加或删除一台memcache都会造成数据的全部失效,一致性hash就是为了解决这个问题,把失效数据降到最低,相关资料可以google一下!
php实现效率有一定的缺失,如果要高效率,还是写扩展比较好
经测试,5个memcache,每个memcache生成100个虚拟节点,set加get1000次,与单个memcache直接set加get慢5倍,所以效率一般,有待优化!
实现过程:
  • memcache的配置 ip+端口+虚拟节点序列号 做hash,使用的是crc32,形成一个闭环。
  • 对要操作的key进行crc32
  • 二分法在虚拟节点环中查找最近的一个虚拟节点
  • 从虚拟节点中提取真实的memcache ip和端口,做单例连接
  1. <?php
  2. /**
  3. * 一致性哈希memcache分布式,采用的是虚拟节点的方式解决分布均匀性问题,查找节点采用二分法快速查找
  4. * the last known user to change this file in the repository <$LastChangedBy: nash.xiong [ DISCUZ_CODE_0 ]gt;
  5. * @author nash.xiong <nash.xiong@gmail.com>
  6. * @copyright Copyright &copy; 2003-2012 phpd.cn
  7. * @license
  8. */
  9. class memcacheHashMap {
  10.  
  11. private $_node = array();
  12. private $_nodeData = array();
  13. private $_keyNode = ;
  14. private $_memcache = null;
  15.  
  16. //每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理]
  17. private $_virtualNodeNum = ;
  18.  
  19. private function __construct() {
  20. /* 放入配置文件 */
  21. $config = array(
  22. '127.0.0.1:11211',
  23. '127.0.0.1:11212',
  24. '127.0.0.1:11213',
  25. '127.0.0.1:11214',
  26. '127.0.0.1:11215'
  27. );
  28.  
  29. if (!$config) throw new Exception('Cache config NULL');
  30. foreach ($config as $key => $value) {
  31. for ($i = ; $i < $this->_virtualNodeNum; $i++) {
  32. $this->_node[sprintf("%u", crc32($value . '_' . $i))] = $value . '_' . $i;
  33. }
  34. }
  35. ksort($this->_node);
  36. }
  37.  
  38. private function __clone(){}
  39.  
  40. /**
  41. * 单例,保证只有一个实例
  42. */
  43. static public function getInstance() {
  44. static $memcacheObj = null;
  45. if (!is_object($memcacheObj)) {
  46. $memcacheObj = new self();
  47. }
  48. return $memcacheObj;
  49. }
  50.  
  51. /**
  52. * 根据key做一致性hash后连接到一台物理memcache服务器
  53. * @param string $key
  54. */
  55. private function _connectMemcache($key) {
  56. $this->_nodeData = array_keys($this->_node);
  57. $this->_keyNode = sprintf("%u", crc32($key));
  58. $nodeKey = $this->_findServerNode();
  59. //如果超出环,从头再用二分法查找一个最近的,然后环的头尾做判断,取最接近的节点
  60. if ($this->_keyNode > end($this->_nodeData)) {
  61. $this->_keyNode -= end($this->_nodeData);
  62. $nodeKey2 = $this->_findServerNode();
  63. if (abs($nodeKey2 - $this->_keyNode) < abs($nodeKey - $this->_keyNode)) $nodeKey = $nodeKey2;
  64. }
  65. var_dump($this->_node[$nodeKey]);
  66. list($config, $num) = explode('_', $this->_node[$nodeKey]);
  67. if (!$config) throw new Exception('Cache config Error');
  68. if (!isset($this->_memcache[$config])) {
  69. $this->_memcache[$config] = new Memcache;
  70. list($host, $port) = explode(':', $config);
  71. $this->_memcache[$config]->connect($host, $port);
  72. }
  73. return $this->_memcache[$config];
  74. }
  75.  
  76. /**
  77. * 采用二分法从虚拟memcache节点中查找最近的节点
  78. * @param unknown_type $m
  79. * @param unknown_type $b
  80. */
  81. private function _findServerNode($m = , $b = ) {
  82. $total = count($this->_nodeData);
  83. if ($total != && $b == ) $b = $total - ;
  84. if ($m < $b){
  85. $avg = intval(($m+$b) / );
  86. if ($this->_nodeData[$avg] == $this->_keyNode) return $this->_nodeData[$avg];
  87. elseif ($this->_keyNode < $this->_nodeData[$avg] && ($avg- >= )) return $this->_findServerNode($m, $avg-);
  88. else return $this->_findServerNode($avg+, $b);
  89. }
  90. if (abs($this->_nodeData[$b] - $this->_keyNode) < abs($this->_nodeData[$m] - $this->_keyNode)) return $this->_nodeData[$b];
  91. else return $this->_nodeData[$m];
  92. }
  93.  
  94. public function set($key, $value, $expire = ) {
  95. return $this->_connectMemcache($key)->set($key, json_encode($value), , $expire);
  96. }
  97.  
  98. public function add($key, $value, $expire = ) {
  99. return $this->_connectMemcache($key)->add($key, json_encode($value), , $expire);
  100. }
  101.  
  102. public function get($key) {
  103. return json_decode($this->_connectMemcache($key)->get($key), true);
  104. }
  105.  
  106. public function delete($key) {
  107. return $this->_connectMemcache($key)->delete($key);
  108. }
  109.  
  110. }
  111.  
  112. $runData['BEGIN_TIME'] = microtime(true);
  113. //测试一万次set加get
  114. for($i=;$i<;$i++) {
  115. $key = md5(mt_rand());
  116. $b = memcacheHashMap::getInstance()->set($key, time(), );
  117. }
  118.  
  119. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],));
  120. $runData['BEGIN_TIME'] = microtime(true); $m= new Memcache;
  121. $m->connect('127.0.0.1', );
  122. for($i=;$i<;$i++) {
  123. $key = md5(mt_rand());
  124. $b = $m->set($key, time(), , );
  125. }
  126. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],));

//测试结果,采用一致性哈希分布效率比原生单台速度相差5倍左右

memcache分布式 [一致性hash算法] 的php实现的更多相关文章

  1. 分布式一致性hash算法

    写在前面  在学习Redis的集群内容时,看到这么一句话:Redis并没有使用一致性hash算法,而是引入哈希槽的概念.而分布式缓存Memcached则是使用分布式一致性hash算法来实现分布式存储. ...

  2. memcache的一致性hash算法使用

    一.概述 1.我们的memcache客户端(这里我看的spymemcache的源码),使用了一致性hash算法ketama进行数据存储节点的选择.与常规的hash算法思路不同,只是对我们要存储数据的k ...

  3. memcache的一致性hash算法

    <?php /** * 一致性哈希memcache分布式,采用的是虚拟节点的方式解决分布均匀性问题,查找节点采用二分法快速查找 * the last known user to change t ...

  4. 关于memcache分布式一致性hash

    consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在 cache 系统中应用越来越广泛: 1  ...

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

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

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

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

  7. Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)

    网站响应速度优化包括集群架构中很多方面的瓶颈因素,这里所说的将页面静态化.实现分布式高速缓存就是其中的一个很好的解决方案... 1)先来看看Nginx负载均衡 Nginx负载均衡依赖自带的 ngx_h ...

  8. 一致性Hash算法在Redis分布式中的使用

    由于redis是单点,但是项目中不可避免的会使用多台Redis缓存服务器,那么怎么把缓存的Key均匀的映射到多台Redis服务器上,且随着缓存服务器的增加或减少时做到最小化的减少缓存Key的命中率呢? ...

  9. 分布式缓存一致性hash算法理解

    今天阅读了一下大型网络技术架构这本苏中的分布式缓存一致性hash算法这一节,针对大型分布式系统来说,缓存在该系统中必不可少,分布式集群环境中,会出现添加缓存节点的需求,这样需要保障缓存服务器中对缓存的 ...

随机推荐

  1. Jquery全选单选功能

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm6.aspx. ...

  2. Quartz2D复习(一)--- 基础知识 / 绘制线段圆弧 / 图片水印 / 截图

    1.Quartz 2D是一个二维绘图引擎,同时支持ios和Mac系统: Quart2D的API是纯C语言的,API来自于Core  Graphics框架: 2.Quartz 2D可以绘制图形(线段/三 ...

  3. XMPP实现登陆注销功能

    XMPP框架的下载与导入等问题请参照 —— XMPP框架的分析.导入及问题解决 DEMO ——XMPP即时通讯(已导入框架)密码:3a7n 这篇我们利用XMPP框架来实现一下登陆功能,先来介绍一下XM ...

  4. android 浅谈Aidl 通讯机制

    服务端: 首先是编写一个aidl文件,注意AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符:AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用 ...

  5. iOS开发之UIAlertView与UIAlertController的详尽用法说明

    本文将从四个方面对IOS开发中UIAlertView与UIAlertController的用法进行讲解: 一.UIAlertView与UIAlertController是什么东东? 二.我们为什么要用 ...

  6. 敏捷软件开发(4)--- TEMPLATE METHOD & STRATEGY 模式

    1.TEMPLATE METHOD 泛型,也就是这个模式,是可以基于泛型的. 我们往往会有一些算法,比如排序算法.它的算法部分,我可以把它放在一个基类里面,这样具体类型的比较可以放在子类里面. 看如下 ...

  7. jQuery Grid With ASP.Net MVC

    jQuery Grid 能够在 ASP.NET MVC 中轻松地实现分页. 排序. 筛选以及 jQuery 插件网格中的 CRUD 操作. 具有以下特征: 时尚的表格数据呈现控件. JavaScrip ...

  8. C# MVC模式 404 500页面设置方法

    <customErrors mode="On" defaultRedirect="Controllers/Action"> <error st ...

  9. Sandcastle----强大的C#文档生成工具

    最近客户索要产品的二次开发类库文档,由于开发过程中并没有考虑过此类文档,而且项目规范比较,持续时间比较长,经手人比较多,还真是麻烦,如果人工制作文档需要是一个比较大的工程.还好有这个文档生成工具,能够 ...

  10. substring -----截取字符串

    var str = "0123456789"; substring alert(str.substring(0));------------"0123456789&quo ...