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图片上传类带图片显示
Nov 25 PHP
什么是MVC,好东西啊
May 03 PHP
探讨Hessian在PHP中的使用分析
Jun 13 PHP
教你如何在CI框架中使用 .htaccess 隐藏url中index.php
Jun 09 PHP
php使用PDO方法详解
Dec 27 PHP
php将日期格式转换成xx天前的格式
Apr 16 PHP
自制PHP框架之模型与数据库
May 07 PHP
thinkPHP5.1框架使用SemanticUI实现分页功能示例
Aug 03 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
Oct 24 PHP
php操作redis数据库常见方法实例总结
Feb 20 PHP
php实现通过stomp协议连接ActiveMQ操作示例
Feb 23 PHP
PHP中SESSION过期设置
Mar 09 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
Smarty中调用FCKeditor的方法
2014/10/27 PHP
PHPstorm启用自动换行的方法详解(IDE)
2020/09/17 PHP
extjs fckeditor集成代码
2009/05/10 Javascript
XmlUtils JS操作XML工具类
2009/10/01 Javascript
JavaScript Cookie 直接浏览网站分网址
2009/12/08 Javascript
JSON 教程 json入门学习笔记
2020/09/22 Javascript
JavaScript小技巧 2.5 则
2010/09/12 Javascript
浅谈javascript 函数表达式和函数声明的区别
2016/01/05 Javascript
微信开发 消息推送实现代码
2016/10/21 Javascript
最细致的vue.js基础语法 值得收藏!
2016/11/03 Javascript
Bootstrap CSS布局之按钮
2016/12/17 Javascript
详解vue项目优化之按需加载组件-使用webpack require.ensure
2017/06/13 Javascript
使用electron实现百度网盘悬浮窗口功能的示例代码
2018/10/24 Javascript
JavaScript实现随机点名器实例详解
2019/05/07 Javascript
JavaScript 面向对象程序设计详解【类的创建、实例对象、构造函数、原型等】
2020/05/12 Javascript
Ant design vue中的联动选择取消操作
2020/10/31 Javascript
vue在图片上传的时候压缩图片
2020/11/18 Vue.js
JavaScript实现瀑布流布局的3种方式
2020/12/27 Javascript
[02:41]DOTA2英雄基础教程 冥魂大帝
2014/01/16 DOTA
python 捕获shell脚本的输出结果实例
2017/01/04 Python
Python+matplotlib实现华丽的文本框演示代码
2018/01/22 Python
Python中最大递归深度值的探讨
2019/03/05 Python
python 基于TCP协议的套接字编程详解
2019/06/29 Python
Django时区详解
2019/07/24 Python
Python使用字典实现的简单记事本功能示例
2019/08/15 Python
django连接oracle时setting 配置方法
2019/08/29 Python
django 取消csrf限制的实例
2020/03/13 Python
初级软件工程师面试题 Junior Software Engineer Interview
2015/02/15 面试题
大学生专业个人学习的自我评价
2013/10/26 职场文书
个人自荐书
2013/12/20 职场文书
先进个人事迹材料
2014/01/25 职场文书
九年级物理教学反思
2014/01/29 职场文书
小学生母亲节演讲稿
2014/05/07 职场文书
出国留学英文自荐信
2015/03/25 职场文书
财务部岗位职责范本
2015/04/14 职场文书
详细介绍Java中的CyclicBarrier
2022/04/13 Java/Android