memcache一致性hash的php实现方法


Posted in PHP onMarch 05, 2015

本文实例讲述了memcache一致性hash的php实现方法。分享给大家供大家参考。具体如下:

最近在看一些分布式方面的文章,所以就用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和端口,做单例连接

<?php

class memcacheHashMap {

        private $_node = array();

        private $_nodeData = array();

        private $_keyNode = 0;

        private $_memcache = null;

        //每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理]

        private $_virtualNodeNum = 200;

        private function __construct() {

                $config = array(//五个memcache服务器

                                                '127.0.0.1:11211',

                                                '127.0.0.1:11212',

                                                '127.0.0.1:11213',

                                                '127.0.0.1:11214',

                                                '127.0.0.1:11215'

                                        );

                if (!$config) throw new Exception('Cache config NULL');

                foreach ($config as $key => $value) {

                        for ($i = 0; $i < $this->_virtualNodeNum; $i++) {

                                $this->_node[sprintf("%u", crc32($value . '_' . $i))] = $value . '_' . $i;//循环为每个memcache服务器创建200个虚拟节点

                        }

                }

                ksort($this->_node);//创建出来的1000个虚拟节点按照键名从小到大排序

        }

        //实例化该类

        static public function getInstance() {

                static $memcacheObj = null;

                if (!is_object($memcacheObj)) {

                        $memcacheObj = new self();

                }

                return $memcacheObj;

        }

        //根据传来的键查找到对应虚拟节点的位置

        private function _connectMemcache($key) {

                $this->_nodeData = array_keys($this->_node);//所有的虚拟节点的键的数组

                $this->_keyNode = sprintf("%u", crc32($key));//算出键的hash值

                $nodeKey = $this->_findServerNode();//找出对应的虚拟节点

                //如果超出环,从头再用二分法查找一个最近的,然后环的头尾做判断,取最接近的节点

                if ($this->_keyNode > end($this->_nodeData)) {

                        $this->_keyNode -= end($this->_nodeData);

                        $nodeKey2 = $this->_findServerNode();

                        if (abs($nodeKey2 - $this->_keyNode) < abs($nodeKey - $this->_keyNode))  $nodeKey = $nodeKey2;

                }

                var_dump($this->_node[$nodeKey]);

                list($config, $num) = explode('_', $this->_node[$nodeKey]);

                if (!$config) throw new Exception('Cache config Error');

                if (!isset($this->_memcache[$config])) {

                        $this->_memcache[$config] = new Memcache;

                        list($host, $port) = explode(':', $config);

                        $this->_memcache[$config]->connect($host, $port);

                }

                return $this->_memcache[$config];

        }

        //二分法根据给出的值找出最近的虚拟节点位置

        private function _findServerNode($m = 0, $b = 0) {

            $total = count($this->_nodeData);

            if ($total != 0 && $b == 0) $b = $total - 1;

            if ($m < $b){

                $avg = intval(($m+$b) / 2);

                if ($this->_nodeData[$avg] == $this->_keyNode) return $this->_nodeData[$avg];

                elseif ($this->_keyNode < $this->_nodeData[$avg] && ($avg-1 >= 0)) return $this->_findServerNode($m, $avg-1);

                else return $this->_findServerNode($avg+1, $b);

            }

                if (abs($this->_nodeData[$b] - $this->_keyNode) < abs($this->_nodeData[$m] - $this->_keyNode))  return $this->_nodeData[$b];

                else return $this->_nodeData[$m];

        }

        public function set($key, $value, $expire = 0) {

                return $this->_connectMemcache($key)->set($key, json_encode($value), 0, $expire);

        }

        public function add($key, $value, $expire = 0) {

                return $this->_connectMemcache($key)->add($key, json_encode($value), 0, $expire);

        }

        public function get($key) {

                return json_decode($this->_connectMemcache($key)->get($key), true);

        }

        public function delete($key) {

                return $this->_connectMemcache($key)->delete($key);

        }

}

$runData['BEGIN_TIME'] = microtime(true);

//测试一万次set加get

for($i=0;$i<10000;$i++) {

        $key = md5(mt_rand());

        $b = memcacheHashMap::getInstance()->set($key, time(), 10);

}

var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));

$runData['BEGIN_TIME'] = microtime(true); $m= new Memcache;

$m->connect('127.0.0.1', 11211);

for($i=0;$i<10000;$i++) {

        $key = md5(mt_rand());

        $b = $m->set($key, time(), 0, 10);

}

var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));

?>

希望本文所述对大家的php程序设计有所帮助。

PHP 相关文章推荐
IIS php环境配置PHP5 MySQL5 ZendOptimizer phpmyadmin安装与配置
Nov 18 PHP
php获得url参数中具有&amp;的值的方法
Mar 05 PHP
php的dl函数用法实例
Nov 06 PHP
php使用PDO方法详解
Dec 27 PHP
/etc/php-fpm.d/www.conf 配置注意事项
Feb 04 PHP
php+mysql+jquery实现简易的检索自动补全提示功能
Apr 15 PHP
PHP文字转图片功能原理与实现方法分析
Aug 31 PHP
PHP数组去重的更快实现方式分析
May 09 PHP
php实现微信公众平台发红包功能
Jun 14 PHP
lnmp安装多版本PHP共存的方法详解
Aug 02 PHP
php高清晰度无损图片压缩功能的实现代码
Dec 09 PHP
phpStudy vscode 搭建debug调试的教程详解
Jul 28 PHP
PHP将session信息存储到数据库的类实例
Mar 04 #PHP
php微信支付之APP支付方法
Mar 04 #PHP
php支付宝手机网页支付类实例
Mar 04 #PHP
php银联网页支付实现方法
Mar 04 #PHP
php随机抽奖实例分析
Mar 04 #PHP
php二维数组合并及去重复的方法
Mar 04 #PHP
php中get_cfg_var()和ini_get()的用法及区别
Mar 04 #PHP
You might like
PHP中的日期及时间
2006/11/23 PHP
怎样才能成为PHP高手?学会“懒惰”的编程
2006/12/05 PHP
非常有用的9个PHP代码片段
2016/04/06 PHP
javascript 弹出窗口中是否显示地址栏的实现代码
2011/04/14 Javascript
jQuery EasyUI API 中文文档 - Parser 解析器
2011/09/29 Javascript
js 有框架页面跳转(target)三种情况下的应用
2013/04/09 Javascript
js如何实现设计模式中的模板方法
2013/07/23 Javascript
Js日期选择器并自动加入到输入框中示例代码
2013/08/02 Javascript
JS获取IP、MAC和主机名的五种方法
2013/11/14 Javascript
H5移动端适配 Flexible方案
2016/10/24 Javascript
如何判断出一个js对象是否一个dom对象
2016/11/24 Javascript
完全深入学习Bootstrap表单
2016/11/28 Javascript
jQuery实现字符串全部替换的方法
2016/12/12 Javascript
Nodejs进阶:express+session实现简易登录身份认证
2017/04/24 NodeJs
Angularjs2不同组件间的通信实例代码
2017/05/06 Javascript
各种选择框jQuery的选中方法(实例讲解)
2017/06/27 jQuery
vue实现折线图 可按时间查询
2020/08/21 Javascript
利用node.js开发cli的完整步骤
2020/12/29 Javascript
[00:47]DOTA2荣耀之路6:天火,天火!
2018/05/30 DOTA
Python实现向服务器请求压缩数据及解压缩数据的方法示例
2017/06/09 Python
Python中矩阵库Numpy基本操作详解
2017/11/21 Python
Python实现的自定义多线程多进程类示例
2018/03/23 Python
使用Python横向合并excel文件的实例
2018/12/11 Python
Django JWT Token RestfulAPI用户认证详解
2019/01/23 Python
Python列表list常用内建函数实例小结
2019/10/22 Python
Python中的四种交换数值的方法解析
2019/11/18 Python
python 爬取疫情数据的源码
2020/02/09 Python
python 比较字典value的最大值的几种方法
2020/04/17 Python
HTML5 图片预加载的示例代码
2020/03/25 HTML / CSS
Maisons du Monde德国:法国家具和装饰的市场领导者
2019/07/26 全球购物
社区十八大感言
2014/01/19 职场文书
小学音乐教学反思
2014/02/05 职场文书
房屋出售授权委托书
2014/10/12 职场文书
考博导师推荐信范文
2015/03/27 职场文书
生死抉择观后感
2015/06/09 职场文书
一文搞懂php的垃圾回收机制
2021/06/18 PHP