今天一个应用的memcache停了两次,在停的过程中,页面出现报错(在这里做漏一件事情,没有立刻去看看页面报什么错误---观察故障现场,而是立刻重启memcache,最后在resin的log中发现相应的错误信息),重启memcache后应用回复正常,在第一次和第二memcache down的过程中我是停留在机器上并观察负载、memcache状态等情况,发现并没有重启,但memcache在我眼皮底下就down。(后来发现同事用了一个比较旧memcache的启动脚本引起,因为该脚本在停止应用的时候把所有名为memcached的进程都杀)。以前所接触的memcache的异常是由于网络原因,但由
于代码中捕捉了异常,所以页面显示会比原来慢点,不至于报错。
因为平时memcache运行都没发生异常情况,所以对memcache变得松懈,刚好这次相应的监控都没部署到这个应用上,同时,今次开发的同事代码没做捕捉异常,所以就发生了页面显示错误信息。
现更新一下自己的认识;
我是这样理解,memcache是一个分布式、不冗余的cache,如果其中一个down应用是会报错误,举个java的例子,并是以简单的memcache调用为例。
一个简单的java客户端连接memcache代码如下(中间清楚了很多代码;,可以只看标示红色):
import java.util.Date;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
/**
* 使用memcached的缓存实用 类.
*
*/
public class MemCached
{
// 创建全局 的唯一实例
protected static MemCachedClient mcc = new MemCachedClient();
protected static MemCached memCached = new MemCached();
// 设置与缓 存服务器的连接池
static {
// 服 务器列表和其权重
String[] servers = {"127.0.0.1:11211"};
Integer[] weights = {3};
// 获 取socke连接池的实例对象
SockIOPool pool = SockIOPool.getInstance();
// 设 置服务器信息
pool.setServers( servers );
pool.setWeights( weights );
// 设 置初始连接数、最小和最大连接数以及最大处理时间
pool.setInitConn( 5 );
pool.setMinConn( 5 );
pool.setMaxConn( 250 );
pool.setMaxIdle( 1000 * 60 * 60 * 6 );
// 设 置主线程的睡眠时间
pool.setMaintSleep( 30 );
// 设 置TCP的参数,连接超时等
pool.setNagle( false );
pool.setSocketTO( 3000 );
pool.setSocketConnectTO( 0 );
// 初 始化连接池
pool.initialize();
// 压 缩设置,超过指定大小(单位为K)的数据都会被压缩
mcc.setCompressEnable( true );
mcc.setCompressThreshold( 64 * 1024 );
}
/**
* 保护型构造方法,不允许 实例化!
*
*/
protected MemCached(){}
/**
* 获取唯一实例.
* @return
*/
public static MemCached getInstance()
{
return memCached;
}
……
public static void main(String[] args)
{
MemCached cache = MemCached.getInstance();
……
}
}
可以见到两个问题:
1. Memcache存在socket的链接
2. 有超时的错误产生
MemCached cache = MemCached.getInstance();
这代码中只创造memcache,却没有对socket连接超时的异常就行捕捉,所以从这看出如果代码的健壮性不够好,如果memcache down了页面就会立刻报错。
如果代码健壮性好,页面不会报错,只是数据库压力会增大,如果对小查询和小对象提取是对应用没什么影响;如果是进行大查询或大对象提取,应用就会有影响,但还是不会报错误,只是提示页面打开会很慢。
增强memcache的监控
1.增加插件对memcache进行进一步监控,已开发完成;
代码在后面贴出;
2.
增加memcache_top工具帮助我们更有利的找问题所在。
3.
增加网上所有的php memcache性能图表(这个是方便自己使用)
4.
增加日志功能(非必须);因为
a memcache的日志功能是通过启动的时候增加vv参数进行;如果要进行日志回滚可能要重启memcache,要不然会出现日志很大。
b memcache内存使用是直接进行内存操作,如果硬件没问题基本不会出现异常;
有出现问题,如无意外在dmesg下能看到;所以在以后我的启动脚本中加入该功能:
如果半个小时内重启三次,就在下一次启动参数中加入vv进行log输出。
check_memcache.py:
#!/usr/bin/python
#coding:utf-8
# check memcached stats
# author: oubin
# version: 1.0
import telnetlib,sys,os
import cPickle as pickle
IP='127.0.0.1'
tmpPort=os.popen(" xx'").readlines();//获取端口,因为我是写在监控配置文件中。
portLen=len(tmpPort)
if portLen <1 :
print "mc-stats_=0"
print "mc-uptime_=0"
print "mc-limit-maxbytes_=0"
print "mc-hit-rate_=0"
print "mc-requests_=0"
print "mc-hits_=0"
print "mc-sets_=0"
print "mc-cached-mem_=0"
print "mc-bytes_=0"
print "mc-curr-items_=0"
print "mc-curr-connections_=0"
sys.exit(1)
for i in range(0,portLen):
list = tmpPort[i].split('\n')
PORT = list[0]
tn = telnetlib.Telnet()
try:
tn.open(IP,PORT)
except:
print "mc_stats_%s=%s" %(PORT,'1')
sys.exit(2)
tn.read_until('Escape character',0.1)
tn.write('stats\n')
stats=tn.read_until('END',0.1)
tn.close()
if len(stats) < 1:
print "stats=%s" % 'up'
sys.exit(1)
list=stats.split('\n')
stats={}
for i in list:
l=i.split()
if len(l)==3:
stats[l[1]]=l[2]
version=stats['version']
uptime=int(stats['uptime'])
limit_maxbytes=int(stats['limit_maxbytes'])
bytes=int(stats['bytes'])
curr_items=int(stats['curr_items'])
curr_connections=int(stats['curr_connections'])
get_hits=int(stats['get_hits'])
get_misses=int(stats['get_misses'])
cmd_get=int(stats['cmd_get'])
cmd_set=int(stats['cmd_set'])
tmp="/tmp/.memcached/"
path=tmp+PORT
if os.path.exists(path):
cache = open(path,'r')
last_stats=pickle.load(cache)
cache.close()
else:
if not os.path.exists(tmp):
os.makedirs(tmp,mode=511)
cache = open(path, 'wb')
pickle.dump(stats,cache,True)
cache.close()
sys.exit(0)
if len(last_stats)<=0 or (get_hits+get_misses) == 0:
sys.exit(0)
last_uptime=int(last_stats['uptime'])
last_get_hits=int(last_stats['get_hits'])
last_cmd_get=int(last_stats['cmd_get'])
last_cmd_set=int(last_stats['cmd_set'])
hit_rate=int(100*get_hits/(get_hits+get_misses))
rate=(uptime-last_uptime)
requests=(cmd_get-last_cmd_get)/rate
hits=(get_hits-last_get_hits)/rate
sets=(cmd_set-last_cmd_set)/rate
cached_mem=int(100*bytes/limit_maxbytes)
limit_maxbytes=int(limit_maxbytes/1048576)
bytes=int(bytes/1048576)
cache = open(path, 'wb')
pickle.dump(stats,cache,True)
cache.close()
print "mc-stats_%s=%s" %(PORT,'0')
print "mc-uptime_%s=%d" %(PORT,int(uptime/86400))
print "mc-limit-maxbytes_%s=%d" %(PORT,limit_maxbytes)
print "mc-hit-rate_%s=%d" %(PORT,hit_rate)
print "mc-requests_%s=%d" %(PORT,requests)
print "mc-hits_%s=%d" %(PORT,hits)
print "mc-sets_%s=%d" %(PORT,sets)
print "mc-cached-mem_%s=%d" %(PORT,cached_mem)
print "mc-bytes_%s=%d" %(PORT,bytes)
print "mc-curr-items_%s=%d" %(PORT,curr_items)
print "mc-curr-connections_%s=%d" %(PORT,curr_connections)
以上脚本大家可以通过增加相应的参数进行提取。
|
文件: | check_memcached.zip |
大小: | 1KB |
下载: | 下载 |
|
2.memcache_top(perl脚本)我自己使用是进行了一些修改。大家也可以按需修改。
|
文件: | memcache-top.zip |
大小: | 4KB |
下载: | 下载 |
|
3.php页面显示,只在某个机器上搭个php环境,把这个memcache.php文件放上去就行了。我自己
使用也是做一些修改,大家也可以按需修改。
|
文件: | memcache.zip |
大小: | 7KB |
下载: | 下载 |
|
其他的还有配合cacti,nagio进行的监控
阅读(2239) | 评论(0) | 转发(0) |