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的FTP学习(四)
Oct 09 PHP
实现了一个PHP5的getter/setter基类的代码
Feb 25 PHP
PHP中调用ASP.NET的WebService的代码
Apr 22 PHP
基于php常用正则表达式的整理汇总
Jun 08 PHP
php数组编码转换示例详解
Mar 11 PHP
解密ThinkPHP3.1.2版本之模板继承
Jun 19 PHP
PHP curl模拟登录带验证码的网站
Nov 30 PHP
php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
Dec 21 PHP
PHP分页初探 一个最简单的PHP分页代码的简单实现
Jun 21 PHP
PHP实现的DES加密解密封装类完整实例
Apr 29 PHP
PHP中有关长整数的一些操作教程
Sep 11 PHP
PHP如何开启Opcache功能提升程序处理效率
Apr 27 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
phpmyadmin MySQL 加密配置方法
2009/07/05 PHP
PHP网站安装程序制作的原理、步骤、注意事项和示例代码
2010/08/01 PHP
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
PHP连接MySQL数据库操作代码实例解析
2020/07/11 PHP
动态改变textbox的宽高的js
2006/10/26 Javascript
javascript 日历提醒系统( 兼容所有浏览器 )
2009/04/07 Javascript
JavaScript 代码压缩工具小结
2012/02/27 Javascript
如何获取select下拉框的值(option没有及有value属性)
2013/11/08 Javascript
js 右侧浮动层效果实现代码(跟随滚动)
2015/11/22 Javascript
jQueryUI DatePicker 添加时分秒
2016/06/04 Javascript
输入法的回车与消息发送快捷键回车的冲突解决方法
2016/08/09 Javascript
微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】
2017/12/09 Javascript
vue 微信授权登录解决方案
2018/04/10 Javascript
详解如何在vue项目中使用lodop打印插件
2018/09/27 Javascript
JS原生带缩略图的图片切换效果
2018/10/10 Javascript
怎样使你的 JavaScript 代码简单易读(推荐)
2019/04/16 Javascript
探索JavaScript中私有成员的相关知识
2019/06/13 Javascript
python益智游戏计算汉诺塔问题示例
2014/03/05 Python
Python中的异常处理学习笔记
2015/01/28 Python
python3.6 +tkinter GUI编程 实现界面化的文本处理工具(推荐)
2017/12/20 Python
Pycharm中安装Pygal并使用Pygal模拟掷骰子(推荐)
2020/04/08 Python
利用css3-animation实现逐帧动画效果
2016/03/10 HTML / CSS
详解CSS3的opacity属性设置透明效果的用法
2016/05/09 HTML / CSS
解决CSS3 transition-delay 属性默认值0不带单位失效的问题
2020/10/29 HTML / CSS
365 Tickets英国:全球景点门票
2019/07/06 全球购物
介绍一下Ruby的多线程处理
2013/02/01 面试题
大学生村官典型材料
2014/01/12 职场文书
长安大学毕业生自我鉴定
2014/01/17 职场文书
知名企业招聘广告词大全
2014/03/18 职场文书
入职担保书怎么写
2014/05/12 职场文书
企业宣传工作方案
2014/06/02 职场文书
党员“四风”方面存在问题及整改措施
2014/09/24 职场文书
小升初自荐信怎么写
2015/03/26 职场文书
无婚姻登记记录证明
2015/06/18 职场文书
单位提档介绍信
2015/10/22 职场文书
MySQL里面的子查询的基本使用
2021/08/02 MySQL