缓存方案的基本要求:避免单点故障;较好的性能和稳定性;便于运维管理。
常见方案如下:缺点:一般用于ubuntu平台,在centos上安装较复杂。
Mcrouter是一个支持memcached实例的代理,被facebook用于遍布全球的数十个集群几千个服务器之间控制流量。它适用于大规模的缓存处理中,在峰值的时候,mcrouter处理接近50亿的请求/秒。
1.支持标准开源的memcached ASCII编码协议
支持memcahed协议的所有客户端无需做任何修改即可被mcrouter支持。
2.多种hash算法
支持consistent hashing算法,集群扩容只有少量数据需要迁移。也可根据需要自定义其他hash算法:weighted ch3,crc32,HostIdRoute 等。
3.前缀路由
mcrouter可以根据key前缀把客户端分配到不同的memcahed池,从而实现集群中的memcache实例分组。
4.memcached池备份
通过将add\set\delete分发到两个池,而get只从其中一个池中获取数据,实现两个池的备份。当其中一个池有实例宕机时,可以从备份池中获取数据。
5.热加载
mcrouter监控它所有的配置文件,一旦检测到任何配置文件被修改,mcrouter的一个后台线程将自动的重新加载并分析这些文件。该过程对客户端完全透明。
6.自动故障转移
一旦某实例无响应,mcrouter将直接将相关请求转移到另一个可用的实例。同时,后台继续向无响应实例发送心跳请求,只要该实例恢复正常,mcrouter将会重新启用这个实例。该过程对客户端完全透明。
{
"pools": {
"A": {
"servers": [
"192.168.188.150:11211",
"192.168.188.150:11212",
"192.168.188.150:11213",
"192.168.188.150:11214",
"192.168.188.150:11215",
"192.168.188.150:11216",
"192.168.188.150:11217",
"192.168.188.150:11218",
"192.168.188.150:11219",
]
}
},
"route": "PoolRoute|A"
}
{
"pools": {
"A": {
"servers": [
"192.168.188.150:11211",
"192.168.188.150:11212",
"192.168.188.150:11213",
"192.168.188.150:11214",
"192.168.188.150:11215",
"192.168.188.150:11216",
"192.168.188.150:11217",
"192.168.188.150:11218",
"192.168.188.150:11219",
"192.168.188.150:11220",
"192.168.188.150:11221",
]
}
},
"route": "PoolRoute|A"
}
{
"pools": {
"pool1": { "servers": [ "192.168.188.150:11211","192.168.188.150:11212" ] },
"pool2": { "servers": [ "192.168.188.150:11213","192.168.188.150:11214" ] },
"pool3": { "servers": [ "192.168.188.150:11215","192.168.188.150:11216" ] },
"common_cache": { "servers": [ "192.168.188.150:11217","192.168.188.150:11218" ] }
},
"route": {
"type": "PrefixSelectorRoute",
"policies": {
"p1": "PoolRoute|pool1",
"p2": "PoolRoute|pool2",
"p3": "PoolRoute|pool3"
},
"wildcard": "PoolRoute|common_cache"
}
}
{
"pools": {
"p1": {
"servers": [
"192.168.188.150:11211"
]
},
"p2": {
"servers": [
"192.168.188.150:11212"
]
}
},
"route": "PoolRoute|p1",
"route": "PoolRoute|p2",
"route": {
"type": "FailoverRoute",
"children": [ "PoolRoute|p1","PoolRoute|p2" ],
"failover_errors": [ "tko" ]
}
}
//add
public boolean add(String key, Object val)
public boolean add(String key, Object val, Date expireDate)
public boolean add(String key, Object val, Integer hashCode)
public boolean add(String key, Object val, Date expireDate, Integer hashCode)
//set
public boolean set(String key, Object val)
publicboolean set(String key, Object val, Date expireDate)
publicboolean set(String key, Object val, Integer hashCode)
publicboolean set(String key, Object val, Date expireDate, Integer hashCode)
//get
public Object get(String key)
publicObject get(String key, Integer hashCode)
publicObject get(String key, Integer hashCode, Boolean asString)
//delete
public boolean delete(String key)
//gets and cas
public MemcachedItem gets(String key)
publicMemcachedItem gets(String key, Integer hashCode)
publicboolean cas(String key, Object val, long casUnique)
publicboolean cas(String key, Object val, Date expireDate, long casUnique)
publicboolean cas(String key, Object val, Integer hashCode, long casUnique)
publicboolean cas(String key, Object val, Date expireDate, Integer hashCode, long casUnique)
//incr and decr
public long incr(String key)
publiclong incr(String key, long inc)
publiclong incr(String key, long inc, Integer hashCode)
publiclong decr(String key)
publiclong decr(String key, long inc)
publiclong decr(String key, long inc, Integer hashCode)
//thread safe way to incr and decr
public long addOrIncr(String key)
publiclong addOrIncr(String key, long inc)
publiclong addOrIncr(String key, long inc, Integer hashCode)
publiclong addOrDecr(String key)
publiclong addOrDecr(String key, long inc)
publiclong addOrDecr(String key, long inc, Integer hashCode)
客户端并发数 |
memcache |
mcrouter |
请求数比较 memcache/mcrouter |
||
每秒请求数 |
CPU负载 |
每秒请求数 |
CPU负载 |
||
1 |
3500 |
4% |
1500 |
5% |
2 |
10 |
20000 |
13% |
9600 |
22% |
2 |
50 |
43000 |
30% |
23000 |
32% |
2 |
100 |
104000 |
60% |
40300 |
48% |
3 |
500 |
320000 |
89% |
64600 |
55% |
5 |
1000 |
323000 |
90% |
87000 |
82% |
4 |
访问方式 |
每秒请求数 |
每个请求耗时(微秒) |
远程访问memcache |
43000 |
23 |
本地访问mcrouter |
31300 |
32 |
远程访问mcrouter |
23000 |
43 |
Memcache实例数 |
每秒请求数 |
性能下降 |
代理服务器CPU负载 |
1 |
25564 |
0% |
23% |
2 |
24667 |
4% |
30% |
4 |
24093 |
6% |
23% |
8 |
24473 |
4% |
32% |
16 |
23290 |
9% |
33% |
32 |
21810 |
15% |
23% |
客户端并发线程 |
sleep时间(秒) |
每秒请求数 |
Socket连接 |
平均延迟(毫秒) |
CPU负载 |
5000 |
0.25 |
20000 |
4900 |
1 |
23% |
10000 |
0.5 |
20000 |
5600 |
1.6 |
24% |
20000 |
1 |
20000 |
7500 |
1.1 |
23% |
30000 |
1.5 |
20000 |
14800 |
7.4 |
30% |
单个客户端并发线程 |
每秒请求 |
1 |
1512 |
5 |
5785 |
10 |
5928 |
50 |
5524 |
100 |
5979 |
vrrp_script chk_11200 {
script "
16:08:02 set k9 true
16:08:03 set k10 true
16:08:04 set k11 true
11081 [main] ERROR com.danga.MemCached.MemCachedClient - ++++ exception thrown while writing bytes to server on set
11081 [main] ERROR com.danga.MemCached.MemCachedClient - 您的主机中的软件中止了一个已建立的连接。
java.io.IOException: 您的主机中的软件中止了一个已建立的连接。
……
16:08:05 set k12 false
16:08:06 set k13 false
16:08:08 set k14 false
16:08:10 set k15 true
16:08:17 set k16 true
16:08:18 set k17 true
/etc/security/limits.conf
* soft nofile 102400
* hard nofile 102400
* soft nproc 102400
* hard nproc 102400
/etc/pam.d/login
session required /lib64/security/pam_limits.so
/etc/sysctl.conf
net.ipv4.ip_local_port_range = 9000 65500
net.ipv4.tcp_keepalive_time = 600
cat myflavor-standalone
{
"libmcrouter_options": {
"config_file": "/root/mcrouter/mcrouter.conf",
"async_spool": "/root/mcrouter/spool",
"num_proxies": "4",
"reset_inactive_connection_interval": "0"
},
"standalone_options": {
"log_file": "/root/mcrouter/mcrouter.log",
"ports": "11200"
}
}
{
"pools": {
"pool1": {
"servers": [
"192.168.188.150:11211",
"192.168.188.150:11212",
"192.168.188.150:11213",
"192.168.188.150:11214",
"192.168.188.150:11215",
"192.168.188.150:11216",
"192.168.188.150:11217",
"192.168.188.150:11218"
]
},
"pool1_bak": {
"servers": [
"192.168.188.150:11219",
]
}
},
"route": {
"type": "FailoverRoute",
"default_policy": "PoolRoute|pool1",
"children": [ "PoolRoute|pool1", "PoolRoute|pool1_bak" ],
"failover_errors": [ "tko" ]
}
}
前缀 |
项目 |
功能模块 |
分配日期 |
p1aaa |
项目A |
主站session共享 |
20150929 |
p1aab |
项目B |
主站session共享 |
20150929 |
可用性
每秒SET次数 echo "stats" | nc ip 11211 | grep cmd_set | awk '{print $3}'
每秒GET次数 echo "stats" | nc ip 11211 | grep cmd_get | awk '{print $3}'
每秒GET命中次数 echo "stats" | nc ip 11211 | grep get_hits | awk '{print $3}'
每秒被踢出的未过期KV数量 echo "stats" | nc ip 11211 | grep evictions | awk '{print $3}'
每秒回收的已到期KV数量 echo "stats" | nc ip 11211 | grep “ reclaimed “ | awk '{print $3}'
各SLAB中“最老KV的存活时间“的最小值 echo "stats items" | nc ip 11211 | grep age | awk '{print $3}' | sort | head -1