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 相关文章推荐
php基础知识:类与对象(5) static
Dec 13 PHP
帖几个PHP的无限分类实现想法~
Jan 02 PHP
PHP 操作文件的一些FAQ总结
Feb 12 PHP
提高PHP性能的编码技巧以及性能优化详细解析
Aug 24 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(五)
Jun 23 PHP
PHP使用GETDATE获取当前日期时间作为一个关联数组的方法
Mar 19 PHP
php求一个网段开始与结束IP地址的方法
Jul 09 PHP
PHP执行shell脚本运行程序不产生core文件的方法
Dec 28 PHP
php实现的二叉树遍历算法示例
Jun 15 PHP
PHP设计模式之工厂模式定义与用法详解
Apr 03 PHP
PHP实现数据库的增删查改功能及完整代码
Apr 18 PHP
php实例化一个类的具体方法
Sep 19 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
把77A收信机改造成收音机
2021/03/02 无线电
php数字转汉字代码(算法)
2011/10/08 PHP
PHP下打开phpMyAdmin出现403错误的问题解决方法
2013/05/23 PHP
PHP使用GIFEncoder类处理gif图片实例
2014/07/01 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
对YUI扩展的Gird组件 Part-1
2007/03/10 Javascript
利用js对象弹出一个层
2008/03/26 Javascript
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
2008/09/27 Javascript
jquery attr 设定src中含有&amp;(宏)符号问题的解决方法
2011/07/26 Javascript
NodeJS Web应用监听sock文件实例
2015/02/18 NodeJs
jQuery实现点击行选中或取消CheckBox的方法
2016/08/01 Javascript
node.js文件上传处理示例
2016/10/27 Javascript
scroll事件实现监控滚动条并分页显示(zepto.js)
2016/12/18 Javascript
Angular 4.x 路由快速入门学习
2017/05/03 Javascript
vue表单绑定实现多选框和下拉列表的实例
2017/08/12 Javascript
AngularJS中scope的绑定策略实例分析
2017/10/30 Javascript
Layui给数据表格动态添加一行并跳转到添加行所在页的方法
2018/08/20 Javascript
Vue.js点击切换按钮改变内容的实例讲解
2018/08/22 Javascript
electron + vue项目实现打印小票功能及实现代码
2018/11/25 Javascript
详解package.json版本号规则
2019/08/01 Javascript
[02:33]DOTA2英雄基础教程 司夜刺客
2013/12/04 DOTA
在Python程序中操作MySQL的基本方法
2015/07/29 Python
Python程序中设置HTTP代理
2016/11/06 Python
python 开发的三种运行模式详细介绍
2017/01/18 Python
python3 模拟登录v2ex实例讲解
2017/07/13 Python
Python使用flask框架操作sqlite3的两种方式
2018/01/31 Python
Python爬虫基础之XPath语法与lxml库的用法详解
2018/09/13 Python
python代码 输入数字使其反向输出的方法
2018/12/22 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
如何快速一次性卸载所有python包(第三方库)呢
2020/10/20 Python
CSS3制作精致的照片墙特效
2016/06/07 HTML / CSS
日语专业毕业生自荐信
2013/11/11 职场文书
买房协议书范本
2014/10/23 职场文书
社区灵活就业证明
2014/11/03 职场文书
捐助倡议书
2015/01/19 职场文书
MySQL系列之开篇 MySQL关系型数据库基础概念
2021/07/02 MySQL