Memcached集群介绍
由于Memcached服务器与服务器之间没有任何通讯,并且不进行任何数据复制备份,所以当任何服务器节点出现故障时,会出现单点故障,如果需要实现HA,则需要通过另外的方式来解决。
通过Magent缓存代理,防止单点现象,缓存代理也可以做备份,通过客户端连接到缓存代理服务器,缓存代理服务器连接缓存连接服务器,缓存代理服务器可以连接多台Memcached机器可以将每台Memcached机器进行数据同步。如果其中一台缓存服务器down机,系统依然可以继续工作,如果其中一台Memcached机器down掉,数据不会丢失并且可以保证数据的完整性。
搭建Memcached集群

先在三台测试机上安装好libevent和memcached,启动memcached实例;
然后在51和52上安装好magent,启动magent实例。
安装和启动memcached实例
1
2
3
<code>/usr/local/bin/memcached</code> <code>-d -m 256 -u memcached -l 192.168.11.51 -p 11211 -c 1024 -P </code><code>/var/run/memcached/memcached</code><code>.pid</code>
<code>/usr/local/bin/memcached</code> <code>-d -m 256 -u memcached -l 192.168.11.52 -p 11211 -c 1024 -P </code><code>/var/run/memcached/memcached</code><code>.pid</code>
<code>/usr/local/bin/memcached</code> <code>-d -m 256 -u memcached -l 192.168.11.68 -p 11211 -c 1024 -P </code><code>/var/run/memcached/memcached</code><code>.pid</code>
安装和启动magent实例
笔者在测试magent-0.6.tar.gz时,该版本在与最新版memcached运行下不够稳定,如下配置以magent-0.5.tar.gz为示例。
1. 安装magent到/usr/local下:
4
5
6
<code>cd</code> <code>/usr/local</code>
<code>mkdir</code> <code>magent </code>
<code>cd</code> <code>magent </code>
<code>wget http:</code><code>//memagent</code><code>.googlecode.com</code><code>/files/magent-0</code><code>.5.</code><code>tar</code><code>.gz </code>
<code>(若无法直接访问,可先下载安装包后上传到服务器上) </code>
<code>tar</code> <code>zxvf magent-0.5.</code><code>tar</code><code>.gz</code>
2. 修改配置:
在ketama.h文件开头添加
<code>#ifndef SSIZE_MAX </code>
<code>#define SSIZE_MAX 32767 </code>
<code>#endif</code>
<code>ln</code> <code>-s </code><code>/usr/lib64/libm</code><code>.so </code><code>/usr/lib64/libm</code><code>.a</code>
<code>/sbin/ldconfig</code>
<code>sed</code> <code>-i </code><code>"s#LIBS = -levent#LIBS = -levent -lm#g"</code> <code>Makefile </code>
<code>vi</code> <code>Makefile</code>
将
<code>CFLAGS = -Wall -O2 -g</code>
修改为:
<code>CFLAGS = -lrt -Wall -O2 -g</code>
保存
3. 编译:
<code>make</code>
输出如下信息:
<code>gcc -lrt -Wall -O2 -g -c -o magent.o magent.c </code>
<code>gcc -lrt -Wall -O2 -g -c -o ketama.o ketama.c </code>
<code>gcc -lrt -Wall -O2 -g -o magent magent.o ketama.o -levent –lm</code>
4. 查看命令帮助:
<code>.</code><code>/magent</code> <code>–h</code>
7
8
9
10
11
12
13
14
15
<code>memcached agent v0.4 Build-Date: Apr 21 2015 09:21:10 </code>
<code>Usage: </code>
<code>-h this message </code>
<code>-u uid </code>
<code>-g gid </code>
<code>-p port, default is 11211. (0 to disable tcp support) </code>
<code>-s ip:port, set memcached server ip and port </code>
<code>-b ip:port, set backup memcached server ip and port </code>
<code>-l ip, local bind ip address, default is 0.0.0.0 </code>
<code>-n number, set max connections, default is 4096 </code>
<code>-D don't go to background </code>
<code>-k use ketama key allocation algorithm </code>
<code>-f file, unix socket path to listen on. default is off </code>
<code>-i number, set max keep alive connections for one memcached server, default is 20 </code>
<code>-v verbose</code>
5. 启动magent实例
<code>/usr/local/magent/magent</code> <code>-u root -n 4096 -l 192.168.11.51 -p 11200 -s 192.168.11.51:11211 -s 192.168.11.52:11211 -b 192.168.11.68:11211 </code>
<code>/usr/local/magent/magent</code> <code>-u root -n 4096 -l 192.168.11.52 -p 11200 -s 192.168.11.51:11211 -s 192.168.11.52:11211 -b 192.168.11.68:11211</code>
测试流程
登录51上的magent,存储key1到key5:
16
17
18
19
20
21
22
23
24
25
26
<code>[root@mongo01 ~]# telnet 192.168.11.51 11200</code>
<code>Trying 192.168.11.51...</code>
<code>Connected to 192.168.11.51.</code>
<code>Escape character is '^]'.</code>
<code>stats</code>
<code>memcached agent v0.4</code>
<code>matrix 1 -> 192.168.11.51:11211, pool size 0</code>
<code>matrix 2 -> 192.168.11.52:11211, pool size 0</code>
<code>END</code>
<code>set key1 0 0 1</code>
<code>1</code>
<code>STORED</code>
<code>set key2 0 0 2</code>
<code>22</code>
<code>set key3 0 0 3</code>
<code>333</code>
<code>set key4 0 0 4</code>
<code>4444</code>
<code>set key5 0 0 5</code>
<code>55555</code>
<code>quit</code>
<code>Connection closed by foreign host.</code>
登录到51上的memcached,获取到了key2和key4:
<code>[root@mongo01 ~]# telnet 192.168.11.51 11211</code>
<code>get key1</code>
<code>get key2</code>
<code>VALUE key2 0 2</code>
<code>get key3</code>
<code>get key4</code>
<code>VALUE key4 0 4</code>
<code>get key5</code>
登录到52上的memcached,获取到了key1、key3和key5:
<code>[root@mongo02 ~]# telnet 192.168.11.52 11211</code>
<code>Trying 192.168.11.52...</code>
<code>Connected to 192.168.11.52.</code>
<code>VALUE key1 0 1</code>
<code>VALUE key3 0 3</code>
<code>VALUE key5 0 5</code>
登录到68上的memcached,获取到了key1到key5:
<code>[root@szlnmp01 ~]# telnet 192.168.11.68 11211</code>
<code>Trying 192.168.11.68...</code>
<code>Connected to 192.168.11.68.</code>
停掉52的memcached进程,通过51上的magent获取到了key1到key5:
<code>kill</code> <code>`</code><code>cat</code> <code>/var/run/memcached/memcached</code><code>.pid`</code>
<code>[root@mongo01 magent]# telnet 192.168.11.51 11200</code>
恢复52的memcached进程,通过51上的magent,只获取到了key2和key4:
通过以上测试可以得出结论:
1. 通过magent的连接池存放的值会分别存在magent代理的所有memcached上去。
2. 如果有一个memcached宕机通过magent代理方式还能取到值。
3. 如果memcached修复重启后通过magent代理方式取到的值就会为Null,这是由于memcache重启后里边的值随着memcache服务的停止就消失了(因为在内存中),但是magent是通过key进行哈希计算分配到某台机器上的,memcache重启后会还从这台机器上取值,所有取到的值就为空。
解决办法:
1. 在每次memcache宕机修复后可以写一个程序把集群中的其他memcache的所有信息全给拷贝到当前宕机修复后的memcache中。
2. 自己写代理,当从一个memcached服务上取到的值为Null时再去其他memcached上取值。
注意事项:
magent的调用方式同memcached一样,客户端可以不用改代码即可实现切换到magent模式下。
缓存与DB的同步
比较保险的做法是:查询的时候从缓存中取,add、updae、delete的时候同时操作缓存与DB。
当然你也可以定时同步缓存与DB的数据,不同的业务应该有不同的选择。
magent-0.6版本相关的错误汇总
产生如下错误:
<code>gcc -Wall -g -O2 -I/usr/local/include -m64 -c -o magent.o magent.c </code>
<code>magent.c: In function ‘writev_list’: </code>
<code>magent.c:729: error: ‘SSIZE_MAX’ undeclared (first use in this function) </code>
<code>magent.c:729: error: (Each undeclared identifier is reported only once </code>
<code>magent.c:729: error: for each function it appears in.) </code>
<code>make: *** [magent.o] Error 1</code>
解决方法:
再次make
产生如下错误:
<code>gcc -Wall -g -O2 -I/usr/local/include -m64 -c -o ketama.o ketama.c </code>
<code>gcc -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o </code>
<code>usr/lib64/libevent.a /usr/lib64/libm.a </code>
<code>gcc: /usr/lib64/libevent.a: No such file or directory </code>
<code>gcc: /usr/lib64/libm.a: No such file or directory </code>
<code>make: *** [magent] Error 1</code>
<code>ln</code> <code>-s </code><code>/usr/lib64/libm</code><code>.so </code><code>/usr/lib64/libm</code><code>.a </code>
找到LIBS = /usr/lib64/libevent.a /usr/lib64/libm.a
按照如下格式修改:
LIBS = /usr/<libevent的安装路径>/libevent.a /usr/lib64/libm.a
如:LIBS = /usr/lib/libevent.a /usr/lib64/libm.a
保存
<code>gcc -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib/libevent.a /usr/lib64/libm.a </code>
<code>/usr/lib/libevent.a(event.o): In function `gettime': </code>
<code>/tmp/libevent-2.0.22-stable/event.c:370: undefined reference to `clock_gettime' </code>
<code>/usr/lib/libevent.a(event.o): In function `detect_monotonic': </code>
<code>/tmp/libevent-2.0.22-stable/event.c:340: undefined reference to `clock_gettime' </code>
<code>collect2: ld returned 1 exit status </code>
<code>CFLAGS = -Wall -g -O2 -I/usr/local/include $(M64)</code>
<code>CFLAGS = -lrt -Wall -g -O2 -I/usr/local/include $(M64)</code>
输出为:
<code>gcc -lrt -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib/libevent.a /usr/lib64/libm.a</code>
<code> </code>