摘要
http://wenku.baidu.com/link?url=eUmpWDGFiFguyQLxwmXwRYmbnW7Wm1Bo79dGoomSnmOPWDIA5-FFSTNRI7MBQq8QGsSGjyR1aFzIqeCe8xXNRZZOfm8LZ5xrck2quS6LZt_

http://blog.csdn.net/mayongzhan/article/details/4298834

http://bbs.phpchina.com/forum.php?mod=viewthread&tid=233897

参考1

参考2

参考3

最近在看一些分布式方面的文章,所以就用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 = 0;
  14. private $_memcache = null;
  15.  
  16. //每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理]
  17. private $_virtualNodeNum = 200;
  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 = 0; $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 = 0, $b = 0) {
  82. $total = count($this->_nodeData);
  83. if ($total != 0 && $b == 0) $b = $total - 1;
  84. if ($m < $b){
  85. $avg = intval(($m+$b) / 2);
  86. if ($this->_nodeData[$avg] == $this->_keyNode) return $this->_nodeData[$avg];
  87. elseif ($this->_keyNode < $this->_nodeData[$avg] && ($avg-1 >= 0)) return $this->_findServerNode($m, $avg-1);
  88. else return $this->_findServerNode($avg+1, $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 = 0) {
  95. return $this->_connectMemcache($key)->set($key, json_encode($value), 0, $expire);
  96. }
  97.  
  98. public function add($key, $value, $expire = 0) {
  99. return $this->_connectMemcache($key)->add($key, json_encode($value), 0, $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=0;$i<10000;$i++) {
  115. $key = md5(mt_rand());
  116. $b = memcacheHashMap::getInstance()->set($key, time(), 10);
  117. }
  118.  
  119. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));
  120. $runData['BEGIN_TIME'] = microtime(true); $m= new Memcache;
  121. $m->connect('127.0.0.1', 11211);
  122. for($i=0;$i<10000;$i++) {
  123. $key = md5(mt_rand());
  124. $b = $m->set($key, time(), 0, 10);
  125. }
  126. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));
  127. //测试结果,采用一致性哈希分布效率比原生单台速度相差5倍左右

记录memcache分布式策略及算法的更多相关文章

  1. memcache分布式 [一致性hash算法] 的php实现

    最近在看一些分布式方面的文章,所以就用php实现一致性hash来练练手,以前一般用的是最原始的hash取模做分布式,当生产过程中添加或删除一台memcache都会造成数据的全部失效,一致性hash就是 ...

  2. MemCache分布式缓存的一个bug

    Memcached分布式缓存策略不是由服务器端至支持的,多台服务器之间并不知道彼此的存在.分布式的实现是由客户端代码(Memcached.ClientLibrary)通过缓存key-server映射来 ...

  3. memcache分布式部署的原理分析

    下面本文章来给各位同学介绍memcache分布式部署的原理分析,希望此文章对你理解memcache分布式部署会有所帮助哦.   今天在封装memcache操作类库过程中,意识到一直以来对memcach ...

  4. 美团技术分享:深度解密美团的分布式ID生成算法

    本文来自美团技术团队“照东”的分享,原题<Leaf——美团点评分布式ID生成系统>,收录时有勘误.修订并重新排版,感谢原作者的分享. 1.引言 鉴于IM系统中聊天消息ID生成算法和生成策略 ...

  5. memcache分布式小实例

    <?php /** * 分布式的 memcache set 实现 */ /** * 创建缓存实现memcache 添加分布式服务器 并设置权限 */ function createCache() ...

  6. 分布式一致性hash算法

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

  7. memcache 分布式缓存

    转载地址:http://www.cnblogs.com/phpstudy2015-6/p/6713164.html 作者:那一叶随风 1.memcached分布式简介 memcached虽然称为“分布 ...

  8. 理解分布式id生成算法SnowFlake

    理解分布式id生成算法SnowFlake https://segmentfault.com/a/1190000011282426#articleHeader2 分布式id生成算法的有很多种,Twitt ...

  9. 分布式 ID 生成算法 — SnowFlake

    一.概述 分布式 ID 生成算法的有很多种,Twitter 的 SnowFlake 就是其中经典的一种. SnowFlake 算法生成 ID 的结果是一个 64bit 大小的整数,它的结构如下图: 1 ...

随机推荐

  1. CSU 1424 Qz’s Maximum All One Square

    原题链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1424 逐渐找到做这种题的感觉了. 二分法.g[i][j]存储坐标(i, j)的值,s[i ...

  2. django的orm获取字段去重值

    如果要用django的ORM获取一个表字段所有可能的去重值. 网上找了很多,都是用distinct关键字,但如何没有随后的order_by, 还是达不到要求的. 最后搞定. 参考URL http:// ...

  3. TPC-H数据导入MySQL教程

    0. TPC-H是啥 TPC-H是TPC提供的一个benchmark,用来模拟一个现实中的商业应用,可以生成一堆虚构的数据,且自带一些查询,可以导入到各种数据库中来模拟现实需求,检查性能. 具体是怎样 ...

  4. fastdfs5.11+centos7.2 按照部署(三)【转载】

    1.测试 前面两篇博文已对FastDFS的安装和配置,做了比较详细的讲解.FastDFS的基础模块都搭好了,现在开始测试下载. 1.1 配置客户端 同样的,需要修改客户端的配置文件: vim /etc ...

  5. linux 驱动程序 HelloWorld

    Linux驱动可以直接编译进内核,也可以以模块的形式进行加载,前者比较复杂,本文就以模块的形式加载! vi helloi_driver.c #include <linux/init.h> ...

  6. java.lang.ClassCastException: android.widget.ImageButton异常处理

    在调程序时总是出现异常关闭的现象,log显示: 03-26 07:58:09.528: E/AndroidRuntime(398): Caused by: java.lang.ClassCastExc ...

  7. mysql 事务回滚

    begindeclare t_error integer default 0;  //添加变量t_error并赋初始值为0declare continue handler for sqlexcepti ...

  8. 将内存图像数据封装成QImage V2

    转:http://www.cnblogs.com/bibei1234/p/3161555.html 如何将内存图像数据封装成QImage 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行 ...

  9. HDU 6183 Color it

    线段树. 假设只有一种颜色,因为每次询问有一个$x$一定是$1$,那么我可以想办法找出每一个$y$最小的$x$是多少,如果最小的都不符合,那么一定不符合,因为更新变成了单点更新,询问是区间询问最小值, ...

  10. java 数组冒泡排序、转置(降序)

    1.java 数组冒泡排序 排序的基本原理(升序): 原始数据:  2 .1 .9 .0 .5 .3 .7 .6 .8: 第一次排序: 1  .2 .0 .5 .3 .7 .6 .8 .9 : 第二次 ...