Memcached搭建

一、 Memcached介绍

1. 什么是Memcached**

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的HashMap,它并不提供冗余(复制其HashMap条目),当某个服务器停止运行或崩溃了,所有存放在服务器上的键/值对都将丢失。但目前Memcached的客户端和代理程序可以提供多服务器的并联方式,可以提供一定的处理能力。

2. Memcached的特点**

memcached作为高速运行的分布式缓存服务器,具有以下的特点

Ø 协议简单

Ø 基于libevent的事件处理

Ø 内置内存存储方式

Ø memcached不互相通信的分布式

3. Memcached的存储方式

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。

4. Memcached分布式介绍

Memcached虽然称为“分布式“缓存服务器,但服务器端并没有“分布式”的功能。Memcached的分布式完全是有客户端实现的。现在我们就看一下memcached是怎么实现分布式缓存的。

n Memcached的分布式方法

Memcached的分布式方法简单来说,就是“根据服务器台数的余数进行分散”。 求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。

缺点:

余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。 那就是当添加或移除服务器时,缓存重组的代价相当巨大。 添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器, 从而影响缓存的命中率,有可能会发生无法提供正常服务的情况。

5. \解决方案1:采用******Consistent Hashing****算法****

Consistent Hashing如下所示:首先求出memcached服务器(节点)的哈希值, 并将其配置到0~232的圆(continuum)上。 然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。 如果超过2^32仍然找不到服务器,就会保存到第一台memcached服务器上。

img

从上图的状态中添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化 而影响缓存的命中率,但Consistent Hashing中,只有在continuum上增加服务器的地点逆时针方向的 第一台服务器上的键会受到影响。

img

因此,Consistent Hashing最大限度地抑制了键的重新分布。 而且,有的Consistent Hashing的实现方法还采用了虚拟节点的思想。 使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。 因此,使用虚拟节点的思想,为每个物理节点(服务器) 在continuum上分配100~200个点。这样就能抑制分布不均匀, 最大限度地减小服务器增减时的缓存重新分布。现在可以轻而易举地添加memcached服务器了。

缓存多副本

缓存多副本主要是用于在缓存数据存放时存储缓存数据的多个副本,以防止缓存失效。缓存失效发生在以下几种情况:

\1. 缓存超时被移除(正常失效)

\2. 缓存由于存储空间限制被移除(异常失效)

\3. 由于缓存节点变化而导致的缓存失效(异常失效)

在缓存多副本的情况下,需要重新考虑缓存的分布式分布策略。其次缓存的多个副本实际本身是可能的多个读的节点,可以做为分布式的并行读,这是另外一个可以考虑的问题。

n 缓存数据的一致性问题

缓存数据尽量只读,因此缓存本身是不适合大量写和更新操作的数据场景的。对于读的情况下,如果存在数据变化,一种是同时更新缓存和数据库。一种是直接对缓存数据进行失效处理。

6. *解决方案2:采用Magent缓存代理服务器*

采用 Magent 缓存代理,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存服务器,缓存代理服务器可以连接多台Memcached机器

二、 *Magent缓存代理搭建过程*

1. *Memcached集群及Magent缓存代理逻辑设计图*

Magent代理服务器:2台,分别为 192.168.1.2:12000、192.168.1.3:12000
Memcached主服务器:3台,分别为 192.168.1.4:11211、192.168.1.5:11211、192.168.1.6:11211 
Memcached备服务器:2台,分别为 192.168.1.5:11211、192.168.1.6:11211

img

2. *系统环境*

[root@localhost ~]# cat /etc/redhat-release 
CentOS release 6.6 (Final)
[root@localhost ~]# uname -r
2.6.32-504.el6.x86_64

3. *搭建Memcahced服务器*

在 192.168.1.4、192.168.1.5、192.168.1.6、192.168.1.7、192.168.1.8 上分别编译安装并运行Memcached

安装过程

rpm -qa libevent libevent-devel nc telnet
yum install -y libevent libevent-devel nc telnet
rpm -qa memcached
yum install memcached –y
memcached -m 16m -p 11211 -d -u root -c 8192     #启动一个实例

4. *搭建Magent代理服务器*

cd /usr/local
mkdir magent
cd magent/
wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/memagent/magent-0.6.tar.gz
tar zxvf magent-0.6.tar.gz
/sbin/ldconfig
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
1、在ketama.h中开头加入 
vim ./ketama.h
#ifndef SSIZE_MAX 
#define SSIZE_MAX 32767 
#endif 
2、安装依赖库
yum install -y glibc-devel 
\cp /usr/lib64/libm.so /usr/lib64/libm.a 
ln -s /usr/lib/libevent* /usr/lib64/ 
3、编辑Makefile 
vim ./Makefile 
CFLAGS = -Wall -g -O2 -I/usr/local/include $(M64) 
修改为 
CFLAGS = -lrt -Wall -g -O2 -I/usr/local/include $(M64) 
4、重新编译
/sbin/ldconfig 
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile 
make 
\cp magent /usr/bin/magent

5. *magent命令详解:*

[root@localhost magent]# magent
please provide -s "ip:port" argument

memcached agent v0.6 Build-Date: Jul 13 2016 03:13:50
Usage:
  -h this message
  -u uid
  -g gid
  -p port, default is 11211. (0 to disable tcp support)
  -s ip:port, set memcached server ip and port
  -b ip:port, set backup memcached server ip and port
  -l ip, local bind ip address, default is 0.0.0.0
  -n number, set max connections, default is 4096
  -D don't go to background
  -k use ketama key allocation algorithm
  -f file, unix socket path to listen on. default is off
  -i number, set max keep alive connections for one memcached server, default is 20
  -v verbose
在 192.168.1.2、192.168.1.3 上分别运行 magent:
magent -u root -n 51200 -l 192.168.1.2 -p 12000 -s 192.168.1.4:11211 -s 192.168.1.5:11211 -s 192.168.1.6:11211 -b 192.168.1.7:11211 -b 192.168.1.8:11211

6. 在web server服务器配置

cd /server/tools/
wget http://pecl.php.net/get/memcache-2.2.7.tgz
tar zxvf memcache-2.2.7.tgz 
cd memcache-2.2.7
/application/php/bin/phpize 
./configure --enable-memcache --with-php-config=/application/php/bin/php-config --with-zlib-dir
make
make install

在php.ini中加入如下内容:

extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/memcache.so

修改php.ini中的session.save_handler及session.save_path为如下内容

session.save_handler = memcache
session.save_path = "tcp://memcached服务器ip:11211"

7. 测试缓存数据的分布情况

以前,我们用PHP连接多台Memcached服务器,做分布式缓存时,参考代码如下:

$memcache = new Memcache;
$memcache->addServer('localhost', 11211);
$memcache->addServer('localhost', 11212);
$memcache->addServer('localhost', 11213);
for ($i = 0; $i < 1000; $i++)
{
    $memcache->set($i, $i, 0, 1000);
}

现在,代码还是那段代码,只不过连接的主机不是Memcached服务器了,而是 Magent代理服务器,给 addServer()方法传参时,传入的是Magent主机IP与端口!测试代码如下:

$mem = new \Memcache();

$host = '192.168.1.2';
$port = '12000 ';
$mem->connect($host, $port);

$key1 = 'snsgou1';
$value1 = '1';
$mem->add($key1, $value1);

$key2 = 'snsgou2';
$value2 = '2';
$mem->add($key2, $value2);

$key3 = 'snsgou3';
$value3 = '3';
$mem->add($key3, $value3);

$key4 = 'snsgou4';
$value4 = '4';
$mem->add($key4, $value4);

$key5 = 'snsgou5';
$value5 = '5';
$mem->add($key5, $value5);

$key6 = 'snsgou6';
$value6 = '6';
$mem->add($key6, $value6);

说明:

1、PHP连接magent,把缓存key1交给magent,magent根据自身的配置参数,再加上一定的哈希算法,会计算出key1存在3台主Memcached服务器的某一台上,然后以同样的算法,将key1也在2台备用的Memcached服务器中的某一台上,再存一份数据。即,主服务器是分布式存储的,同时,从服务器也是分布式存储的;

2、在PHP获取缓存数据key1时,magent一旦得知数据所存的那台主Memcached服务器挂掉了,它就会转向从备用的Memcached服务器中获取数据。注意:服务器的定位选择算法跟存的时候是一样的。

3、有个缺陷,当 down 掉的那台主Memcached服务器重新恢复正常后,Memcahed里是没有数据的,即数据全部丢失,但此时 备用的Memcached服务器 又不会将数据同步到 主服务器。

4、通过Memcached管理软件MemAdmin(点击下载)去查看上述数据分布情况,如下:

192.168.1.4 存有 snsgou6,snsgou3
192.168.1.5 存有 snsgou4,snsgou1
192.168.1.6 存有 snsgou5,snsgou2
192.168.1.7 存有 snsgou5,snsgou3,snsgou1
192.168.1.8 存有 snsgou4,snsgou6,snsgou2

5、PHP连接代理的时候,最好每次随机性只连一台,这样,一旦某台代理挂了(即连不上),可切换连另外一台代理服务器。而随机性地去连,又保证了一定的负载均衡。

服务器技术交流群请加微信 YJZyjz