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面向对象编程快速入门
Oct 09 PHP
用PHP和ACCESS写聊天室(一)
Oct 09 PHP
dedecms 制作模板中使用的全局标记图文教程
Mar 11 PHP
手把手教你使用DedeCms的采集的图文教程
Mar 11 PHP
php 字符串压缩方法比较示例
Jan 23 PHP
smarty模板引擎从php中获取数据的方法
Jan 22 PHP
PHP实现获取FLV文件的时间
Feb 10 PHP
php实现格式化多行文本为Js可用格式
Apr 15 PHP
php文件扩展名判断及获取文件扩展名的N种方法
Sep 12 PHP
PHP自定义函数格式化json数据示例
Sep 14 PHP
PHP实现简单ajax Loading加载功能示例
Dec 28 PHP
PHP创建单例后台进程的方法示例
May 23 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 危险函数解释 分析
2009/04/22 PHP
php入门学习知识点二 PHP简单的分页过程与原理
2011/07/14 PHP
php urlencode()与urldecode()函数字符编码原理详解
2011/12/06 PHP
比较简单的百度网盘文件直链PHP代码
2013/03/24 PHP
php实现保存submit内容之后禁止刷新
2014/03/19 PHP
PHP获取文件行数的方法
2015/06/10 PHP
Laravel获取当前请求的控制器和方法以及中间件的例子
2019/10/11 PHP
B/S开发中常用javaScript技术与代码
2007/03/09 Javascript
jquery图片放大镜功能的实例代码
2013/03/26 Javascript
Javascript基础教程之JavaScript语法
2015/01/18 Javascript
JavaScript随机生成信用卡卡号的方法
2015/04/07 Javascript
javascript中JSON.parse()与eval()解析json的区别
2016/05/19 Javascript
JavaScript实现Fly Bird小游戏
2016/12/15 Javascript
JavaScript原生实现观察者模式的示例
2017/12/15 Javascript
layui 实现加载动画以及非真实加载进度的方法
2019/09/23 Javascript
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
2021/01/05 Vue.js
使用python实现baidu hi自动登录的代码
2013/02/10 Python
Python判断以什么结尾以什么开头的实例
2018/10/27 Python
法国购买二手电子产品网站:Asgoodasnew
2020/03/27 全球购物
计算 s=(x*y)1/2,用两个宏定义来实现
2016/08/11 面试题
体育专业个人的求职信范文
2013/09/21 职场文书
学前教育毕业生自荐信
2013/10/29 职场文书
配件采购员岗位职责
2013/12/03 职场文书
煤矿班组长的职责
2013/12/25 职场文书
高中历史教学反思
2014/02/08 职场文书
学习全国两会精神心得体会范文
2014/03/17 职场文书
公司办公室岗位职责
2014/03/19 职场文书
关于安全演讲稿
2014/05/09 职场文书
公司募捐倡议书
2014/05/14 职场文书
房地产活动策划方案
2014/05/14 职场文书
支部书记四风问题对照检查材料
2014/10/04 职场文书
2015年维修工作总结
2015/04/25 职场文书
风雨哈佛路观后感
2015/06/03 职场文书
回复函范文
2015/07/14 职场文书
2016年共产党员公开承诺书
2016/03/24 职场文书
2019中小学生安全过暑期倡议书
2019/06/24 职场文书