Linux下Memcache分布式部署方案与使用magent代理安装搭建memcached集群环境、单点故障解决方案

Mmemcached存在的问题

本身没有内置分布式功能,无法实现使用多台Memcache服务器来存储不同的数据,最大程度的使用相同的资源;无法同步数据,容易造成单点故障。(memagent代理实现集群)

在 Memcached中可以保存的item数据量是没有限制的,只要内存足够 。
Memcached单进程最大使用内存为2G,要使用更多内存,可以分多个端口开启多个Memcached进程
最大30天的数据过期时间,设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA 60*60*24*30控制
最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH 250控制
单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK 1048576进行控制,
它是默认的slab大小
最大同时连接数是200,通过 conn_init()中的freetotal进行控制,最大软连接数是1024,通过settings.maxconns=1024 进行控制
跟空间占用相关的参数:settings.factor=1.25, settings.chunk_size=48, 影响slab的数据占用和步进方式

memcached是一种无阻塞的socket通信方式服务,基于libevent库,由于无阻塞通信,对内存读写速度非常之快。
memcached分服务器端和客户端,可以配置多个服务器端和客户端,应用于分布式的服务非常广泛。
memcached作为小规模的数据分布式平台是十分有效果的。

memcached是键值一一对应,key默认最大不能超过128个字节,value默认大小是1M,也就是一个slabs,如果要存2M的值(连续的),不能用两个slabs,因为两个slabs不是连续的,无法在内存中存储,故需要修改slabs的大小,多个key和value进行存储时,即使这个slabs没有利用完,那么也不会存放别的数据。

Memcache的分布式介绍

memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。服务器端仅包括内存存储功能,其实现非常简单。至于memcached的分布式,则是完全由客户端程序库实现的。这种分布式是memcached的最大特点。

如何理解Memcached的分布式

这里多次使用了“分布式”这个词,但并未做详细解释。 现在开始简单地介绍一下其原理,各个客户端的实现基本相同。
下面假设memcached服务器有node1~node3三台, 应用程序要保存键名为“tokyo”“kanagawa”“chiba”“saitama”“gunma” 的数据。

1

图1 分布式简介:准备

首先向memcached中添加“tokyo”。将“tokyo”传给客户端程序库后,客户端实现的算法就会根据“键”来决定保存数据的memcached服务器。服务器选定后,即命令它保存“tokyo”及其值。

2

图2 分布式简介:添加时

同样,“kanagawa”“chiba”“saitama”“gunma”都是先选择服务器再保存。

接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。 函数库通过与数据保存时相同的算法,根据“键”选择服务器。 使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。 只要数据没有因为某些原因被删除,就能获得保存的值。

3

图3 分布式简介:获取时

这样,将不同的键保存到不同的服务器上,就实现了memcached的分布式。 memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障
无法连接,也不会影响其他的缓存,系统依然能继续运行。

集群配置

由于Memcached服务器与服务器之间没有任何通讯,并且不进行任何数据复制备份,所以当任何服务器节点出现故障时,会出现单点故障,如果需要实现HA,则需要通过另外的方式来解决。

通过Magent缓存代理,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存服务器,缓存代理服务器可以连接多台Memcached机器可以将每台Memcached机器进行数据同步。如果其中一台缓存服务器down机,系统依然可以继续工作,如果其中一台Memcached机器down掉,数据不会丢失并且可以保证数据的完整性。具体可以参考:http://code.google.com/p/memagent/

Memcache集群的实现

memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。

magent是一个memcached代理软件(memcached agent),又叫memagent,其项目网址为:
https://github.com/wangmh/memagent,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存服务器。
它提供的功能及特点有:
1、和每个memcache server保持多个长连接,效果是减少memcache server保持的连接数量及创建销毁连接的开销。不过,memcache本身就支持大并发连接,这个功能也就没什么特别的说道。
2、支持memcache的binary协议命令,实现请求的转发。
3、和memcache一样,基于libevent的事件驱动来处理IO。
4、支持ketama 的一致性hash算法。
5、支持memcache backup集群,当memcache集群有机器挂了,memagent会将get请求转向memcache backup集群。这个功能对于cache的稳定性要求高的场景下会有用武之地。

就提供的功能而言,memagent是个很简单的东西。对于较大的memcache集群,可以考虑搭一套memagent作为proxy使用。

magent的hash算法

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

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

4

Linux下的Memcache集群环境搭建

环境:CentOS release 6.5

搭建memcached集群环境,先要安装gcc
# yum -y install gcc
如果出现如下错误:

Error: Package: glibc-headers-2.12-1.132.el6.x86_64 (base)
           Requires: kernel-headers >= 2.2.1
Error: Package: glibc-headers-2.12-1.132.el6.x86_64 (base)
           Requires: kernel-headers
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

解决方法:修改文件
vi /etc/yum.conf

exclude=kernel*
前加注释即可解决,此参数的意思是排除安装或更新kernel开头的软件,而我们安装gcc需要依赖kernel相关的软件glibc-headers-2.12-1.80.el6_3.5.x86_64

在root目录下创建soft目录
# cd /root/
# mkdir soft

安装libevent

检查是否安装了libevent软件
# rpm -qa|grep libevent

编译安装libevent

# cd /root/soft/
# wget http://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
# tar -zxvf libevent-2.0.21-stable.tar.gz
# cd libevent-2.0.21-stable
# ./configure --prefix=/usr
# make && make install
# cd ../

测试是否安装成功:
# ls -al /usr/lib | grep libevent

yum安装libevent

也可以用yum直接安装libevent
yum install libevent libevent-devel

编译安装Memcached

# cd /root/soft/
# wget http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz
# tar -zxvf memcached-1.4.15.tar.gz
# cd memcached-1.4.15/
# ./configure --with-libevent=/usr
# make && make install
# cd ../

测试是否安装成功:
# ls -al /usr/local/bin/mem*

或启动一个memcached进程
# memcached -m 1 -u root -d -l 192.168.1.151 -p 11211

查看是否启动成功了

# ps aux|grep memcached

显示两行 root,则说明安装成功了,如下所示:

root     11952  0.0  0.0 331112  1104         Ssl  15:09   0:00 memcached -m 1 -u root -d -l 192.168.1.151 -p 11211
root     11959  0.0  0.0 103240   796 pts/1    S+   15:09   0:00 grep memcached

编译安装magent

编译安装magent-0.6到/usr/local/下(推荐安装magent-0.5稳定版本,因为测试发现magent-0.6虽是最新版本,但是还存在问题,不稳定,第二次访问magent始终会堵塞在那里,只能set一个值。测试了magent-0.5是稳定版本,没有出现只能set一个值的现象,遂推荐安装magent-0.5版本,不过此问题也可以通过修改源码的方式来解决,解决方案参考(重点参考第8楼):https://code.google.com/p/memagent/issues/detail?id=4#makechanges )

cd /usr/local
mkdir magent
cd magent/
wget http://memagent.googlecode.com/files/magent-0.6.tar.gz
解压的文件中ketama.* 是一致性hash的实现
tar -zxvf magent-0.6.tar.gz

vi ketama.h
在开头加入
#ifndef SSIZE_MAX
# define SSIZE_MAX      32767
#endif

############magent-0.6版本修改内容start############
vi Makefile (magent-0.6版本)

LIBS = /usr/lib64/libevent.a /usr/lib64/libm.a
改为
LIBS = -lrt /usr/lib64/libevent.a /usr/lib64/libm.a

CFLAGS = -Wall -g -O2 -I/usr/local/include $(M64)
改为
CFLAGS = -lrt -Wall -g -O2 -I/usr/local/include $(M64)
############magent-0.6版本修改内容end##############

############magent-0.5版本修改内容start############
vi Makefile (magent-0.5版本)

CFLAGS = -Wall -O2 -g
改为
CFLAGS = -lrt -Wall -O2 -g

sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
############magent-0.5版本修改内容end##############

cp /usr/lib/libevent.a /usr/lib64
ln -s /usr/lib64/libm.so /usr/lib64/libm.a
/sbin/ldconfig

make
cp magent /usr/bin/magent
cd ../

测试magent是否安装成功:

1.启动一个magent进程

magent -u root -n 51200 -l 192.168.1.151 -p 12000 -s 192.168.1.151:11211

2.查看是否启动成功了

ps aux|grep magent

显示两行 root,则说明安装成功了,如下所示:

root 11720 0.0 0.0 10972 588 Ss 13:51 0:00 magent -u root -n 51200 -l 192.168.1.151 -p 12000 -s 192.168.1.151:11211 -s 192.168.1.151:11212 -b 192.168.1.151:11213
root 11974 0.0 0.0 103240 792 pts/1 R+ 15:12 0:00 grep magent[/code]

注: 之前的安装过程中,我总是只显示一行:root 11974 0.0 0.0 103240 792 pts/1 R+ 15:12 0:00 grep magent,但是执行magent命令又不报错,可是查看magent进程,老是没有,老是启动不起来,其实还是magent没有安装成功,所以这边必须要看到两行,才能说明启动成功。

安装可能会出错,可以到该地址看看:http://ruancl.blog.51cto.com/2699729/850951
其它参考地址:http://blog.csdn.net/laosubitu/article/details/22198613

magent工作方式

1.get操作,先到普通mem上读取;如果失败,再到备份mem上读取(即服务器失效会导致两次读,不过只是特殊情况下的处理,可以接受)
2.如果一次get多个key的值,会逐个执行1中的步骤
3.delete,incr,decr,add,set,replace,prepend,append,cas,同时操作{普通mem,备份mem}

* 写操作:先操作备份men,再操作普通mem
* 不关联两者之间操作的成功/失败

4.client从magent上断开,不影响magent保持与集群server的链接
5.建议:client和magent部署在一起,client通过127.0.0.1访问magent时,效率会更高
————-

magent命令参数

-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, max keep alive connections for one memcached server, default is 20
-v verbose

准备测试工具

接着就是进行测试学习了,首先确保telnet服务安装了

查看telnet客户端是否安装:
# rpm -q telnet
若无安装,则执行:
# yum -y install telnet
查看telnet服务端是否安装:
# rpm -q telnet-server
若无安装,则执行:
# yum -y install telnet-server

测试流程

参照:http://blog.s135.com/post/393/ 其中使用的是magent-0.5

我尝试了0.5和最新的0.6,但里面提到的重启后的” 由于这两台Memcached重启后无数据,因此magent取得的将是空值,尽管11213端口的Memcached还有数据(此问题尚待改进)“,仍然存在

PHP+Memcache实现分布式

我们PHP的PECL中的Memcache扩展能够有效的解决Memcache的分布式问题,主要的接口就是 addServer() 函数,具体关于addServer()函数的实现可以参考该扩展源代码。那么现在就存在第二个问题,就是说无法同步数据,可以理解为MySQL中Master/Slave的机制,就是说如果我们有多台的Memcache服务器,使用addServer函数的话,每个服务器存储的数据都是唯一的,也就是说每个memcached服务器上存储的数据不是统一的,而是各自保存了不通的数据。

配置使用memcache存储session数据

session.save_handler = memcache
session.save_path ="tcp://127.0.0.1:11211"

注意:如果使用的是php的memcached扩展(注意不是memchache扩展)。
按照网上的资料配置php.ini

session.save_handler=memcached
session.save_path="tcp://127.0.0.1:11211"

会发现报错

Warning: Unknown: Failed to write session data (memcached). Please verify that the current setting of session.save_path is correct (tcp://127.0.0.1:11211) in Unknown on line 0

解决方案是把tcp://去掉。经测试,用memcache(不带d)扩展,去掉tcp://后也能正常连接。测试中还发现用memcached扩展时,通过session_id()做为key获取缓存内容始终是空值,但用memcache扩展却是正常,一旦通过memcache扩展设置session后,再通过memcached获取session_id()做为key获取缓存内容就能正常输出,由些我猜测memcached设置不了session_id(此猜测在后面的测试中发现并非如此,而是memcached生成的key为session_id的,自动在前面加了’memc.sess.key.’前缀),但获取值却是正常的。不知道是我配置过程中出错还是什么原因,目前尚未解决这个问题。

其它发现:
1、memcache + magent 不支持session,但支持其它变量的存取
2、memcached + magent 支持session,但是不能通过key为session_id()获取session_id内容,要加上’memc.sess.key.’前缀才可以获取session_id的内容
3、memcache和memcached 不加magent都支持session,但是memcache可通过key为session_id()获取session_id内容,而memcached则不能,memcached的key要加上’memc.sess.key.’前缀才可以获取session_id的内容,由此可知memcache和memcached保存key为session_id()的方式不一样。

参考地址:
http://www.oschina.net/question/191760_88446
http://cubstag.blog.163.com/blog/static/139826788201072351259638/

session.save_handler=memcached
session.save_path="127.0.0.1:11211"

tcp://开头的是memcache扩展的写法,memchached扩展不需要。
参考地址:http://leo108.com/pid-1900.asp

或者某个目录下的 .htaccess :

php_value session.save_handler"memcache"
php_value session.save_path "tcp://127.0.0.1:11211"

再或者在某个一个应用中:

ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");

使用多个 memcached server 时用逗号”,”隔开,并且和Memcache::addServer() 文档中说明的一样,可以带额外的参数”persistent”、”weight”、”timeout”、”retry_interval”等等,类似这样的:”tcp://host1:port1?persistent=1&weight=2,tcp://host2:port2″。

Memcache存取session测试

<!--?php <br ?-->session_start();
if (!isset($_SESSION['TEST'])) {
$_SESSION['TEST'] = time();
}

$_SESSION['TEST3'] = time();

print $_SESSION['TEST'];
print "

";
print $_SESSION['TEST3'];
print "

";
print session_id();
?>

从memcache中取回session数据

<!--?php $memcache = memcache_connect('localhost',11211); var_dump($memcache--->get('19216821213c65cedec65b0883238c278eeb573e077'));
?>

会有看到
string(37)"TEST|i:1177556731;TEST3|i:1177556881;"
这样的输出,证明 session 正常工作
用 memcache 来存储 session 在读写速度上会比 files 时快很多,而且在多个服务器需要共用 session 时会比较方便,将这些服务器都配置成使用同一组 memcached 服务器就可以,减少了额外的工作量。缺点是 session 数据都保存在 memory 中,持久化方面有所欠缺,但对 session 数据来说也不是很大的问题。

另外,WS Memcached Session Handler for PHP 提供一种用session_set_save_handler 来利用 memcached 的方法。

memcached 与 magent组合搭建方案示例

5

magent与memcached 是可以混搭的,不必死板的一个magent s-memcached s-memcached b-memcached

上图此模型已经能够很好的解决一个节点,一组服务器的缓存数据服务,但是如果在北方网通架设了一组服务器,同时在南方电信又架设了另外一组服务器,那么这两组相对独立的节点之间如何做到数据的同步与共享,基于magent与memcached的解决方案如下:

6

需要注意的是,两组magent的配置最好完全一致,比如:

北方的magent配置为:magent s-memcached1 s-memcached2 b-memcached3

那么南方的magent配置也为:magent s-memcached1 s-memcached2 b-memcached3

其顺序都是一致的,因为magent在分配key到memcached上时只是简单的使用散列余数算法。(这是网上部分文章的说法,但根据相关资料,我觉得此处的算法应该是Consistent Hashing算法(http://blog.csdn.net/sparkliang/article/details/5279393),因此我认为跟配置顺序没有关系)

当然如果你够懒,那么你可以直接连接备份magent,因为所有的数据上面都有。

有个特别要注意的地方是:

1.其中一台Memcached死掉,从magent取数据,数据会从备份的Memcached取出,保证用户不受影响.

2.Memcached重启复活,由于这两台Memcached重启后无数据,因此magent取得的将是空值,尽管备份Memcached还有数据。可采用定时维护服务器,恢复memcached。

3.如果Memcached死掉,备份机同时死掉,那么只能说明你够倒霉,此时此刻你或许能见到上帝。

缓存与DB的同步

比较保险的做法是:查询的时候从缓存中取,add、updae、delete的时候同时操作缓存与DB。

当然你也可以定时同步缓存与DB的数据,个人认为不同的业务应该有不同的选择!

我在实际的应用中是同时使用这两种方式,比如用户个人信息之类的内容,就用定时同步的方式

缓存集群的形成历程

缓存集群不是天生就有的,只有应用场景的发展才会引发对集群的需要。

STEP1:无缓存—>STEP2:单机memcached—>STEP3:memcached集群+请求端分片—>STEP4:memcached集群+单台代理—>STEP5:memcached集群+代理集群—>再以后,就没有以后了

1~3阶段都是很轻松的(很多业务能到3阶段已经是规模不小,值得庆幸了);
4阶段后期就会遇到各种压力,要考虑memcached单台失效对后端(很可能是DB或其他持久化存储)突发压力的影响;magent的备份服务器是方法之一,但具体的备份方案需要琢磨,简单的2倍存储代价不小;5阶段要考虑集群+集群的失效,需要引入DNS/名字服务等更低层的网络措施;

经验技巧

最后提出两个使用Memcache的小技巧,第一个是如果是一个有效分布式存储的数据,key的取名是很有学问的,这个可以按照项目需要去做,但是key值不要太长,不会冲突就行。第二个就是每个保存在memcache中的数据不要超过1MB。第三个就是开启一个Memcache进程设置内存不要太多也不要太少,按照自己合适设置就行,尽量最大程度提高对硬件的使用,同样可以采取在一台服务器上开启多个memcached来分担一个memcached并发链接的压力。更多技巧在实际使用长慢慢去总结发现,会发现其实memcahe虽然简单,但是很好用。

magent能够消除单点故障问题,但是不能实现负载均衡。如果要实现负载均衡的话,可能还要再研究一下其他工具。

参考资料

Memcached的代理服务器软件:magent使用小记:http://blog.s135.com/post/393/
一致性hash算法 – consistent hashing:http://blog.csdn.net/sparkliang/article/details/5279393
memcached全面剖析–4. memcached的分布式算法:http://blog.charlee.li/memcached-004/
memcache proxy之memagent介绍分析:http://www.kafka0102.com/2010/01/9.html
Memcached代理软件magent安装小结:http://www.elesos.com/index.php?title=Memcached%E4%BB%A3%E7%90%86%E8%BD%AF%E4%BB%B6magent%E5%AE%89%E8%A3%85%E5%B0%8F%E7%BB%93
memcached 和它的代理:http://my.oschina.net/kakablue/blog/187270
M​e​m​c​a​c​h​e​d​内​存​分​析​、​调​优​、​集​群:http://wenku.baidu.com/view/23821cebe009581b6bd9ebc2.html
Linux下安装搭建Memcached集群环境:http://tim-fly.iteye.com/blog/1756936
Memcached 集群架构方面的问题:http://kb.cnblogs.com/page/69074/
Memagent 负载均衡配置.pptx:http://www.open-open.com/doc/view/97ce1f7d85b7425c9c5bcc09a6bb0b39

发表评论?

0 条评论。

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据