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、优缺点

  相对于取模方式分布式,一致性哈希方式分布式的代码复杂性要高一点,但这也在可以接受的范围内,不构成任何阻碍问题。相反它的优点就非常显著,通过虚拟节点的方式实现,可以使不可控的存储节点能够尽可能的均匀分布在圆环上,从而达到数据均匀缓存在各个主机里。其次增加与删除虚拟节点对于之前缓存的整体数据影响非常小。

时间: 2024-10-12 16:43:27

memcache 分布式缓存的相关文章

memcache分布式缓存

1 什么是memcache 以及memcache有什么作用 Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等.简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度. 2 下载并安装(希望大家自己去动手 印象会更深) 下载memcache 进入cmd ,切换到 memcached.exe 文件所在目录 memcached.exe –d install (1)

MemCache分布式缓存的一个bug

Memcached分布式缓存策略不是由服务器端至支持的,多台服务器之间并不知道彼此的存在.分布式的实现是由客户端代码(Memcached.ClientLibrary)通过缓存key-server映射来实现的,基本原理就是对缓存key求hash值,用hash值对服务器数量进行模运算,该key值被分配到模运算结果为索引的那台server上. Memcached.ClientLibrary对缓存key计算hashcode的核心算法如下: 1 /// <summary> 2 /// Returns a

C# Memcache分布式缓存简单入门

什么是Memcache?能做什么? 以下是百度的观点: memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的.需要频繁访问数据库的网站访问速度提升效果十分显著[1]  .这是一套开放源代码软件,以BSD license授权发布. Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及

php5.4之分布式缓存memcache(windows7下安装配置)

一.安装memcache memcached在windows7上的安装问题 现在安装包:http://www.jb51.net/softs/44843.html   memcache的安装包 错误: 通过cmd命令行进入到D:\webEve\memcached(下载后的解压目录) 运行 memcached.exe -d install 报错" failed to install service or service already installed" 解决方法: www.2cto.c

分布式缓存之 memcache 实现分布式缓存

最近想搞点分布式,但是不知道整点什么,来点简单的吧. 今天讲下memcache的分布式缓存 首先下载memcache的服务器端 百度下可以找到 然后执行安装和开启(关闭服务器)命令(还有其他的命令 可以百度下) memecached -d instal memcached -d start(stop) 然后我们用vs建个console项目 用nuget 下载memcache的c#调用驱动 当然有一些驱动,我选择的是EnyimMemcached github开源地址为:https://github

83-高性能,分布式缓存memcache简析

一. memcached简介 memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in      speeding up dynamic web applications by alleviating database load. (由 LiveJournal旗下的Danga Interactive研发) #高性能,分布

分布式缓存--MVC+EF+Memcache

一.从单机到分布式 现在三台机器组成一个Web的应用集群,其中一台机器用户登录,然后其他另外两台机器如何共享登录状态? 解决方案: 1.AspNet进程外的Session . 2.用数据库存数等钱登录状态. 3.Memcache. 二.为什么用Memcache? 1.解决高并发访问数据库带来的死锁 2.多用户端共享缓存 三.Memcache原理 其实memcache是一种windows服务,客户端发来的请求,都会被Socket服务器端接受到.存数使用键值对存储的.客户端进行存储的时候,就是找最接

Nginx+Memcache+一致性hash算法 实现页面分布式缓存(转)

网站响应速度优化包括集群架构中很多方面的瓶颈因素,这里所说的将页面静态化.实现分布式高速缓存就是其中的一个很好的解决方案... 1)先来看看Nginx负载均衡 Nginx负载均衡依赖自带的 ngx_http_upstream_module . ngx_http_memcached_module两大功能模块,其中一致性hash算法Nginx本身是不支持的,可以借助第三方模块: ngx_http_upstream_consistent_hash 或者直接使用淘宝的Tengine: http://te

分布式缓存——memcache原理

内容:1.什么是Memcached 2.MemCache和MemCached的区别 3.memcache访问模型 4.Memcached作为高速运行的分布式缓存服务器具有以下特点 5.Memcached的内存算法 6.Memcached的缓存策略             7.分布式算法(Consistent Hashing)             8. MemCache的特性和限制总结 1.什么是Memcached        MemCache是一个自由.源码开放.高性能.分布式的分布式内存