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生成带有雪花背景的验证码
Sep 28 PHP
学习php笔记 字符串处理
Oct 19 PHP
php继承的一个应用
Sep 06 PHP
php学习笔记之面向对象
Nov 08 PHP
PHP调试函数和日志记录函数分享
Jan 31 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
Apr 08 PHP
PHP中strcmp()和strcasecmp()函数字符串比较用法分析
Jan 07 PHP
PHP魔术方法使用方法汇总
Feb 14 PHP
php快速排序原理与实现方法分析
May 26 PHP
PHP封装cURL工具类与应用示例
Jul 01 PHP
PHP实现数组根据某个字段进行水平合并,横向合并案例分析
Oct 08 PHP
解决在Laravel 中处理OPTIONS请求的问题
Oct 11 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数组随机排序实现方法
2015/06/13 PHP
浅谈PHP Cookie处理函数
2016/06/10 PHP
Yii框架引入coreseek分页功能示例
2019/02/08 PHP
JavaScript中Array 对象相关的几个方法
2006/12/22 Javascript
编写跨浏览器的javascript代码必备[js多浏览器兼容写法]
2008/10/29 Javascript
javascript replace()正则替换实现代码
2010/02/26 Javascript
JS和JQUERY获取页面大小,滚动条位置,元素位置(示例代码)
2013/12/14 Javascript
javascript的日期对象、数组对象、二维数组使用说明
2014/12/22 Javascript
javascript密码强度校验代码(两种方法)
2015/08/10 Javascript
JS组件Bootstrap Table使用实例分享
2016/05/30 Javascript
基于jQuery实现多标签页切换的效果(web前端开发)
2016/07/24 Javascript
Vue.js学习笔记之常用模板语法详解
2017/07/25 Javascript
IntersectionObserver实现图片懒加载的示例
2017/09/29 Javascript
React组件中的this的具体使用
2018/02/28 Javascript
vue实现Input输入框模糊查询方法
2021/01/29 Javascript
python进阶教程之词典、字典、dict
2014/08/29 Python
python自定义类并使用的方法
2015/05/07 Python
Python 爬虫学习笔记之正则表达式
2016/09/21 Python
PyQt5每天必学之拖放事件
2020/08/27 Python
python3.5绘制随机漫步图
2018/08/27 Python
Python开发网站目录扫描器的实现
2019/02/21 Python
python将字符串list写入excel和txt的实例
2019/07/20 Python
TensorFlow中如何确定张量的形状实例
2020/06/23 Python
TensorFlow保存TensorBoard图像操作
2020/06/23 Python
简单了解如何封装自己的Python包
2020/07/08 Python
自我鉴定思想方面
2013/10/07 职场文书
个人简历的自荐信
2013/10/23 职场文书
硕士研究生自我鉴定范文
2013/12/27 职场文书
人力资源部副职的竞聘演讲稿
2014/01/07 职场文书
开会迟到检讨书
2014/01/08 职场文书
秋季红领巾广播稿
2014/01/27 职场文书
领导干部作风建设自查报告
2014/10/23 职场文书
让子弹飞观后感
2015/06/11 职场文书
一百条裙子读书笔记
2015/07/01 职场文书
Python基本知识点总结
2022/04/07 Python
java版 联机五子棋游戏
2022/05/04 Java/Android