苟哥的笔记本
首页
文章归档
关于
文章归档
关于
首页
编程
正文
php hash算法实现memcached分布式
苟哥
2020-01-18 PM
1556℃
0条
## 一、概述 Memcached和mysql一样,是一款客户端/服务器端(C/S)系统管理软件,有IP、端口,一旦启动,服务器就一直处于可用状态。 Mysql是通过SQL语句管理“磁盘中”的文件,Memcached是通过客户端发送的命令管理“内存中缓存”的数据。 需要缓存的对象或数据以 key/value 对的形式保存在服务器端,key的值通过hash(hash算法的意义在于提供一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系)进行转换,把value传递到对应的具体的某台服务器上。 ![](http://images.kuryun.com/blog/typecho/1579345951.png) Memcached的分布式不是在服务器端实现的,而是在客户端应用中实现的,即通过内置算法制定目标数据的节点。 多台服务器之间是没有任何通信联系的,每台服务器只是对自己的数据进行管理。 * 布置多台Memcached服务器。怎么确定一个数据应该保存到哪台服务器上? * 方案一:普通Hash分布。 * 方案二:一致性Hash分布。 理论参考:https://blog.csdn.net/u011489043/article/details/78944985 ## 二、简单hash算法 ```php function simpleHash(string $key) { $md5 = md5($key); $hash = 0; for ($i = 0; $i < strlen($md5); $i++) { $hash += ord($md5{$i}); } return $hash & 0x7fffffff; } ``` ## 三、普通hash分布 ```php /** * 普通Hash分布 * 取模算法算法的原理是:hash(key)%N */ $servers = ['192.168.1.12', '192.168.1.20']; echo PHP_EOL . '普通hash算法' . PHP_EOL; echo 'save key1 in server:' . $servers[simpleHash('this is key1') % 2] . PHP_EOL; echo 'save key2 in server:' . $servers[simpleHash('this is key2') % 2] . PHP_EOL; ``` ![](http://images.kuryun.com/blog/typecho/1579346084.png) ## 四、一致性哈希 一致性哈希(Consistent Hashing)算法,是分布式系统负载均衡的首选算法,步骤如下: 1. 通常,一个缓存数据的key经过hash后会得到一个32位的值, 将一个32位整数(0~2^32-1)想象成一个环; 1. 通过hash函数把可以处理成整数,在环中找到一个位置与之对应; 1. 使用hash函数处理服务器使用的IP地址,把Memcached服务器群也映射到环上; 1. 把数据映射到服务器上沿着圆环顺时针方向的key出发,直到遇到一个服务器为止,把key对应的数据保存到这个服务器上; 1. 移除服务器受影响的仅是当前服务器节点沿着逆时针出发直到遇到下一个服务器之间的数据,把这些数据按操作4重新映射即可; 1. 添加服务器受影响的是当前服务器节点沿着逆时针出发直到遇到下一个服务器之间的数据,重新映射。 使用PHP实现如下: ```php class FlexiHash { // 保存服务器列表 private $serverList = []; // 记录服务器列表是否已经排过序 private $isSorted = false; /** * 添加一个服务器到服务器列表中 */ public function addServer($server) { $hash = simpleHash($server); if (!isset($this->serverList[$hash])) { $this->serverList[$hash] = $server; } $this->isSorted = false; return true; } /** * 从服务器列表中删除一个服务器 */ public function removeServer($server) { $hash = simpleHash($server); if (isset($this->serverList[$hash])) { unset($this->serverList[$hash]); } $this->isSorted = false; return true; } /** * 在当前的服务器列表中找到合适的服务器存放数据 * 逆时针的圆环 */ public function lookup($key) { $hash = simpleHash($key); if (!$this->isSorted) { krsort($this->serverList, SORT_NUMERIC); $this->isSorted = true; } foreach ($this->serverList as $pos => $server) { if ($hash >= $pos) { return $server; } } $index = array_search(min($this->serverList), $this->serverList); return $this->serverList[$index]; } } // 测试 echo PHP_EOL . '一致性hash算法' . PHP_EOL; $hserver = new FlexiHash(); $hserver->addServer('192.168.1.1'); $hserver->addServer('192.168.1.2'); $hserver->addServer('192.168.1.3'); $hserver->addServer('192.168.1.4'); $hserver->addServer('192.168.1.5'); echo '初始分布' . PHP_EOL; echo 'save key1 in server:' . $hserver->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $hserver->lookup('key2') . PHP_EOL; echo '===============================================' . PHP_EOL; $hserver->removeServer('192.168.1.4'); echo '删除一台服务器后' . PHP_EOL; echo 'save key1 in server:' . $hserver->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $hserver->lookup('key2') . PHP_EOL; echo '===============================================' . PHP_EOL; $hserver->addServer('192.168.1.6'); echo '添加一台服务器后' . PHP_EOL; echo 'save key1 in server:' . $hserver->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $hserver->lookup('key2') . PHP_EOL; ``` **优化:**尽管一致性hash算法具有分布均匀的特性,但是当集群中server数量很少时,他们可能在环中的分布并不是特别均匀,进而导致缓存数据不能均匀分布到所有的server上。为解决这个问题,需要使用虚拟节点的思想:为每个物理节点(server)在环上分配多个节点,这样环上的节点较多,就能抑制分布不均匀。实现例子如下: ```php class ConsistentHashing { // 每个节点对应虚拟节点数 const VIRTUAL_NODES = 150; // server 拥有的hash(节点+虚拟节点) protected $nodes = []; // hash映射server protected $position = []; // 记录服务器列表是否已经排过序 protected $isSorted = false; /** * 添加节点 */ public function addNode($server) { if (isset($this->nodes[$server])) { return; } // 添加节点和虚拟节点 for ($i = 0; $i < self::VIRTUAL_NODES; $i++) { $hash = $this->myHash($server . '#' . $i); $this->position[$hash] = $server; $this->nodes[$server][] = $hash; } $this->isSorted = false; } /** * 删除节点 */ public function delNode($server) { if (!isset($this->nodes[$server])) return; // 循环删除虚拟节点 foreach ($this->nodes[$server] as $val) { unset($this->position[$val]); } // 删除节点 unset($this->nodes[$server]); $this->isSorted = false; } /** * 定位key所属节点 * 顺时针环 */ public function lookup($key) { if (!$this->isSorted) { $this->sortPosition(); $this->isSorted = true; } $hash = $this->myHash($key); // 先取圆环上最小的一个节点,当成结果 $server = current($this->position); // 循环获取相近的节点 foreach ($this->position as $pos => $val) { if ($hash <= $pos) { $server = $val; break; } } return $server; } /** * 按键名顺序排序 */ private function sortPosition() { ksort($this->position); } /** * 自定义哈希函数,把key转为32位符号整数 */ private function myHash($key) { // return sprintf('%u', crc32($key)); return simpleHash($key); } } // 测试 echo PHP_EOL . '另一种hash一致性算法' . PHP_EOL; $ch = new ConsistentHashing(); $ch->addNode('192.168.1.1'); $ch->addNode('192.168.1.2'); $ch->addNode('192.168.1.3'); $ch->addNode('192.168.1.4'); $ch->addNode('192.168.1.5'); echo '初始化' . PHP_EOL; echo 'save key1 in server:' . $ch->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $ch->lookup('key2') . PHP_EOL; echo '==========================================' . PHP_EOL; $ch->delNode('192.168.1.4'); echo '删除节点后' . PHP_EOL; echo 'save key1 in server:' . $ch->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $ch->lookup('key2') . PHP_EOL; echo '==========================================' . PHP_EOL; $ch->addNode('192.168.1.6'); echo '添加一台服务器后' . PHP_EOL; echo 'save key1 in server:' . $ch->lookup('key1') . PHP_EOL; echo 'save key2 in server:' . $ch->lookup('key2') . PHP_EOL; ``` 本文转载自: https://www.cnblogs.com/cshaptx4869/p/10833141.html
标签:
算法
,
PHP
,
memcached分布式
,
hash
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
http://www.i366211.com/archives/78/
上一篇
php7编译安装openssl扩展
下一篇
安装homebrew出现“curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused”
取消回复
评论啦~
提交评论
栏目分类
软件安装
10
开发工具
8
算法
2
测试
1
架构
3
填坑记
2
开源
6
科普
6
私域
2
读书笔记
4
编程
48
运营
3
管理
1
标签云
算法
C程序设计语言
C语言
Java
mysql
PHP
ffmpeg
golang
VueJs
脚手架
VueJs实战项目
Intellij IDEA
Centos7
Hyperf
抖音运营
杰克韦尔奇
跌荡一百年
生成海量测试数据
企业管理
习题2-3
习题2-4
习题2-6
异常分类
File
习题2-7
习题2-8
习题2-9
习题3-3
习题3-4
习题3-5
友情链接
申请
SaaS引擎
机器人框架
京东捡漏