memcache 分布式缓存
转载地址:http://www.cnblogs.com/phpstudy2015-6/p/6713164.html
作者:那一叶随风
1、memcached分布式简介
memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。Memcache集群主机不能够相互通信传输数据,它的“分布式”是基于客户端的程序逻辑算法进一步实现的。
请看下面简图:
根据上图我们简述分析分布式memcached的set与get的过程
set过程:
1、首先通过应用程序set(‘key’,’value’)
2、进入程序,使用key通过逻辑算法得出这个key需要存储的节点位置
3、根据节点位置连接相应的memcached服务器,并发送set命令
get过程:
1、首先通过应用程序get(‘key’)
2、接着使用该key通过逻辑算法获取该key的存储节点
3、根据节点连接相应的memcached服务器,并发送get命令
实现memcached有很多种方式,其中最常用的就是一致哈希思想的分布式(就简称为一致哈希分布式啦)。好的东西当然需要次劣品来衬托它的优点啦,因此在这里除了讲解一致哈希分布式,还会讲到取模分布式。从而进一步分析他们的优缺点。
这里的例子都会采用PHP代码实现,当然啦,最重要的是思想与方法嘛!毕竟这两样东西在任何语言中都是相通的。
2、取模算法方式
何为取模算法方式分布式?就是将key转换为32位的数字,并与memcached服务器的总数进行相除取得余数。而这个余数就是memcached服务器的节点node。有了这个node我们就可以确定memcached服务器,就可以发送命令给memcached执行了。
图示解析:
整个过程上图所示。
1)、PHP代码实现
GetModMemcache.class.php
1 <?php
2 #分布式memcache(取模计算)
3 class GetModMemcache
4 {
5 private $total=‘‘; #存储memcache服务器的总数
6 private $servers=array(); #存储memcache服务器的具体信息
7 /**
8 * @desc 构造函数
9 *
10 * @param $serversArr array | memcache服务器具体信息
11 */
12 public function __construct($serversArr)
13 {
14 $this->total=count($serversArr);
15 $this->servers=$serversArr;
16 }
17
18 /**
19 * @desc 计算$key的存储位置(即哪个服务器)
20 *
21 * @param string | key字符串
22 *
23 * @return int 返回第几个服务器
24 */
25 protected function position($key)
26 {
27 #使用crc32(),将字符串转化为32为的数字
28 return sprintf(‘%u‘,crc32($key))%$this->total; #取余
29 }
30
31 /**
32 * @desc 获取memcached对象
33 *
34 * @param $position int | key的位置信息
35 *
36 * @return object 返回实例化memcached对象
37 */
38 protected function getMemcached($position)
39 {
40 $host=$this->servers[$position][‘host‘]; #服务器池中某台服务器host
41 $port=$this->servers[$position][‘port‘]; #服务器池中某台服务器port
42 $m= new memcached();
43 $m->addserver($host, $port);
44 return $m;
45 }
46
47 /**
48 * @desc 设置key-value值
49 *
50 * @param string | key字符串
51 * @param mixed | 值可以是任何有效的非资源型php类型
52 *
53 * @return 返回结果
54 */
55 public function setKey($key, $value)
56 {
57 $num=$this->position($key);
58 echo $num; #调试用
59 $m=$this->getMemcached($num); #获取memcached对象
60 return $m->set($key, $value);
61 }
62
63 public function getKey($key)
64 {
65 $num=$this->position($key);
66 $m=$this->getMemcached($num);
67 return $m->get($key);
68 }
69
70
71 }
72
73
74 $arr=array(
75 array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11210‘),
76 array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11211‘),
77 array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11212‘),
78 );
79 $mod=new GetModMemcache($arr);
80
81 /*
82 #存储数据
83 $a=$mod->setKey(‘key3‘, ‘key33333‘);
84 echo "<pre>";
85 print_r($a);
86 echo "</pre>";die;
87 */
88 /*
89 #获取数据
90 $b=$mod->getKey(‘key1‘);
91 echo "<pre>";
92 print_r($b);
93 echo "</pre>";die;
94 */
95 ?>
2)、进行相应测试
1、连续插入三个数据
#set(‘key1’,’value11111’); #node=1
#set(‘key2’,’value22222’); #node=1
#set(‘key3’,’value33333’;) #node=0
2、分别telnet连接192.168.95.11:(11210、11211、11212)
11210含有key3数据
11211含有key1、key2数据
11212不含数据
3、使用程序get数据
结果都能够将数据取出来
3)、优缺点
优点:
1、简单实用易理解
2、数据分布均匀
缺点:
1、宕了一台memcached服务器时不能自动调整群组去处理数据,使一部分数据不能使用缓存,一直持续从数据库中获取数据。
2、当需要扩容的时候,增加多台memcached服务器,那么原来已经缓存的数据大多数都不能够被命中,即数据无用。
3、一致哈希算法方式
何为一致哈希算法方式分布式呢?
想象一下,将32位的所有数字从小到大按顺时针分布在一个圆环上;
其次,将每个存储节点赋予一个名字,并通过crc32函数将其转换为32位的数字,此数字就是该memcached服务器的存储节点
接着,将key也通过crc32函数转换为32位的数字,它的所在位置按顺时针方向走第一个遇到的存储节点所对应的memcached服务器就是该key的最终存储服务器。
1)、图像解析
假设node1节点服务器挂了,根据按顺时针最近原则,那么原本存储在node1节点的数据此时也可存储在node3节点中。
假设有扩容的需要,增加的两台memcached服务器,又将会怎么样呢?请看下图分析
结果显示只有少量数据会受到影响,相对于整体数据来说这些影响还是在可接受的范围内。
从上面的图示我们可以很容易发现存在这么个缺点,即是使用crc32函数我们不能控制memcached存储节点的具体位置,并且节点的总数量相对于2的32次方是显得多么的渺小。假若恰好即使这几个存储节点都距离的非常近呢,那么必将有一个memcached服务器承受绝大多数的数据缓存。
请看下图分析:
解决办法:
将一个真实存储节点映射为多个虚拟存储节点,即真实节点+后缀再通过crc32处理(例如:node1_1、node1_2、node1_3、…..、node1_n)
看下图节点分布:
三个真实节点在圆环上就变成了三十个存储节点,这样就可以避免存储节点相距太近而导致数据缓存分布不均匀的问题了,而且存储机制没有任何变化。
2)、PHP代码实现
ConsistentHashMemcache.class.php
1 <?php
2 #分布式memcache 一致性哈希算法(采用环状数据结构)
3 class ConsistentHashMemcache
4 {
5 private $virtualNode=‘‘; #用于存储虚拟节点个数
6 private $realNode=array(); #用于存储真实节点
7 private $servers=array(); #用于存储memcache服务器信息
8 #private $totalNode=array(); #节点总数
9 /**
10 * @desc 构造函数
11 *
12 * @param $servers array | memcache服务器的信息
13 * @param $virtualNode int | 虚拟节点个数,默认64个
14 */
15 public function __construct($servers, $virtualNode=64)
16 {
17 $this->servers=$servers;
18 $this->realNode=array_keys($servers);
19 $this->virtualNode=$virtualNode;
20 }
21
22 /**
23 * @return int 返回32位的数字
24 */
25 private function hash($str)
26 {
27 return sprintf(‘%u‘,crc32($str)); #将字符串转换为32位的数字
28 }
29
30 /**
31 * @desc 处理节点
32 *
33 * @param $realNode array | 真实节点
34 * @param $virturalNode int | 虚拟节点个数
35 *
36 * @return array 返回所有节点信息
37 */
38 private function dealNode($realNode, $virtualNode)
39 {
40 $totalNode=array();
41 foreach ($realNode as $v)
42 {
43 for($i=0; $i<$virtualNode; $i++)
44 {
45 $hashNode=$this->hash($v.‘-‘.$i);
46 $totalNode[$hashNode]=$v;
47 }
48 }
49 ksort($totalNode); #按照索引进行排序,升序
50 return $totalNode;
51 }
52
53 /**
54 * @desc 获取key的真实存储节点
55 *
56 * @param $key string | key字符串
57 *
58 * @return string 返回真实节点
59 */
60 private function getNode($key)
61 {
62 $totalNode=$this->dealNode($this->realNode, $this->virtualNode); #获取所有虚拟节点
63 /* #查看虚拟节点总数
64 echo "<pre>";
65 print_r($totalNode);
66 echo "</pre>";die;
67 */
68 $hashNode=$this->hash($key); #key的哈希节点
69 foreach ($totalNode as $k => $v) #循环总结点环查找
70 {
71 if($k >= $hashNode) #查找第一个大于key哈希节点的值
72 {
73 return $v; #返回真实节点
74 }
75 }
76 return reset($totalNode); #假若总节点环的值都比key哈希节点小,则返回第一个总哈希环的value值
77 }
78
79 /**
80 * @desc 返回memcached对象
81 *
82 * @param $key string | key值
83 *
84 * @return object
85 */
86 private function getMemcached($key)
87 {
88 $node=$this->getNode($key); #获取真实节点
89 echo $key.‘真实节点:‘.$node.‘<br/>‘; #测试使用,查看key的真实节点
90 $host=$this->servers[$node][‘host‘]; #服务器池中某台服务器host
91 $port=$this->servers[$node][‘port‘]; #服务器池中某台服务器port
92 $m= new memcached(); #实例化
93 $m->addserver($host, $port); #添加memcache服务器
94 return $m; #返回memcached对象
95 }
96
97 /**
98 * @desc 设置key-value值
99 */
100 public function setKey($key, $value)
101 {
102 $m=$this->getMemcached($key);
103 return $m->set($key, $value);
104 }
105
106 /**
107 * @desc 获取key中的value
108 */
109 public function getKey($key)
110 {
111 $m=$this->getMemcached($key);
112 return $m->get($key);
113 }
114
115
116 }
117
118 ?>
3)、测试
1、查看所有虚拟节点
一共64*3=132个虚拟节点(虚拟节点设置还是属于偏少的,一般都会设置在100~200)
2、set测试
1 include ‘./ConsistentHashMemcache.class.php‘;
2 header("content-type: text/html;charset=utf8;");
3 $arr=array(
4 ‘node1‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11210‘),
5 ‘node2‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11211‘),
6 ‘node3‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11212‘),
7 );
8
9 $c=new ConsistentHashMemcache($arr);
10
11 #测试set
12 $c->setKey(‘aaa‘, ‘11111‘);
13 $c->setKey(‘bbb‘, ‘22222‘);
14 $c->setKey(‘ccc‘, ‘33333‘);
分别telnet连接192.168.95.11:(11210、11211、11212)
在节点node1中get(‘aaa’)、get(‘bbb’)能取到值
在节点node3中get(‘ccc’)能取到值
3、get测试
1 include ‘./ConsistentHashMemcache.class.php‘;
2 header("content-type: text/html;charset=utf8;");
3 $arr=array(
4 ‘node1‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11210‘),
5 ‘node2‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11211‘),
6 ‘node3‘=>array(‘host‘=>‘192.168.95.11‘, ‘port‘=>‘11212‘),
7 );
8
9 $c=new ConsistentHashMemcache($arr);
10 #测试get
11 echo $c->getKey(‘aaa‘).‘<br/>‘;
12 echo $c->getKey(‘bbb‘).‘<br/>‘;
13 echo $c->getKey(‘ccc‘).‘<br/>‘;
4、优缺点
相对于取模方式分布式,一致性哈希方式分布式的代码复杂性要高一点,但这也在可以接受的范围内,不构成任何阻碍问题。相反它的优点就非常显著,通过虚拟节点的方式实现,可以使不可控的存储节点能够尽可能的均匀分布在圆环上,从而达到数据均匀缓存在各个主机里。其次增加与删除虚拟节点对于之前缓存的整体数据影响非常小。
memcache 分布式缓存的更多相关文章
- MemCache分布式缓存的一个bug
Memcached分布式缓存策略不是由服务器端至支持的,多台服务器之间并不知道彼此的存在.分布式的实现是由客户端代码(Memcached.ClientLibrary)通过缓存key-server映射来 ...
- C# Memcache分布式缓存简单入门
什么是Memcache?能做什么? 以下是百度的观点: memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但目前被许多网站使用以提升网站的访问 ...
- Memcached 分布式缓存系统部署与调试
Memcache 分布式缓存系统部署与调试 工作机制:通过在内存中开辟一块区域来维持一个大的hash表来加快页面访问速度,和数据库是独立的;目前主要用来缓存数据库的数据;存放在内存的数据通过LRU算法 ...
- 分布式缓存之 memcache 实现分布式缓存
最近想搞点分布式,但是不知道整点什么,来点简单的吧. 今天讲下memcache的分布式缓存 首先下载memcache的服务器端 百度下可以找到 然后执行安装和开启(关闭服务器)命令(还有其他的命令 可 ...
- 分布式缓存 memcache学习
1.使用分布式缓存是为了解决多台机器共享信息的问题,通过访问一个ip和端口来可以访问不同的IIS服务器 2.memcache基础原理 在Socket服务器端存储数据是以键值对的形式存储 内存处理的算法 ...
- MemCache分布式内存对象缓存系统
MemCache超详细解读 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而 ...
- 分布式缓存Memcached/memcached/memcache详解及区别
先来解释下标题中的三种写法:首字母大写的Memcached,指的是Memcached服务器,就是独立运行Memcached的后台服务器,用于存储缓存数据的“容器”.memcached和memcache ...
- CYQ.Data 对于分布式缓存Redis、MemCache高可用的改进及性能测试
背景: 随着.NET Core 在 Linux 下的热动,相信动不动就要分布式或集群的应用的需求,会慢慢火起来. 所以这段时间一直在研究和思考分布式集群的问题,同时也在思考把几个框架的思维相对提升到这 ...
- Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)
网站响应速度优化包括集群架构中很多方面的瓶颈因素,这里所说的将页面静态化.实现分布式高速缓存就是其中的一个很好的解决方案... 1)先来看看Nginx负载均衡 Nginx负载均衡依赖自带的 ngx_h ...
随机推荐
- php使用curl模拟多线程发送请求
每个PHP文件的执行是单线程的,但是php本身也可以用一些别的技术实现多线程并发比如用php-fpm进程,这里用curl模拟多线程发送请求.php的curl多线程是通过不断调用curl_multi_e ...
- MSSQL Server 数据库备份还原常用SQL语句及注意
1.备份数据库 backup database db_name to disk='d:\db_name.bak' with format --通过使用with format可以做到覆盖任何现有的备份和 ...
- Springboot入门程序
springboot简化之前的很多xml文件,不需要大量配置xml文件,没有很多xml文件是多么的愉快 下面进入正题,演示简单的入门程序,虽然简单,但足以振奋初学者们 我新建的工程名叫hello,大家 ...
- PAT A1074 Reversing Linked List (25 分)——链表,vector,stl里的reverse
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elem ...
- PAT A1111 Online Map (30 分)——最短路径,dijkstra
Input our current position and a destination, an online map can recommend several paths. Now your jo ...
- PAT A1099 Build A Binary Search Tree (30 分)——二叉搜索树,中序遍历,层序遍历
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...
- centos6安装tomcat8.5
//参考https://www.cnblogs.com/xdp-gacl/p/4097608.html [root@192 ~]# mount /dev/sr0 /mnt/usb1[root@192 ...
- lesson 4:凯撒密码问题
一·问题描述 二·解决过程 1.设计思路 ①人机交互界面 ②加密函数(将字符串的每一个字符提取出来,通过对字符的阿斯克码值进行运算操作实现加密过程,特殊的特殊对待) ③解密函数(与加密函数算法类似) ...
- js判断变量的类型(使用闭包来玩一把)
var Type = (function() { var Type = {}; for (var i = 0, type; type = ['Undefined', 'Null', 'Boolean' ...
- SkylineGlobe 如何实现二次开发加载KML文件
示例代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...