从系统到web一层一层分析系统变卡的原因

现象:

两周前不同客户反馈了几次,状态灯变红,用户的一切操作就很慢了,状态灯是用于对状态的标记,当正常返回的时候是绿灯,非正常情况下则是红灯。有些是涉密用户无法查看,非涉密用户的就只有一会,等会儿就消失了,无法正常跟踪,无法很好重现,支持反馈的也是,ie有问题。

过程:

我们的同事都跟踪了几次,由于不是很好重现,所以不太好排查,并且根据反馈的情况,每次IE都出现问题,firefox有时候出现问题。

系统资源情况:

top查看如下,可以从top图中看出,cpu基本可以忽略不计,内存还有200M左右,交换分区基本上没怎么用,基本可用,再加上buffer(用来存储)和cache(用来存从内存读取的),内存是没有问题的(可用内存=free + buffers + cached),如果出了内存不够的问题, demsg也可看出。

再查看io也是正常的,系统情况一切正常;但是也能看到几个python服务程序占用的内存很高,apache进程的内存在一直上升,可能是内存泄漏可能是请求在增加缓存增加。几个小窍门,M按内存排序,Pcpu排序。从系统到web一层一层分析系统变卡的原因_第1张图片

Postgresql

转到数据库,查看数据库的状态主要是两个表,一个是pg_stat_activity,表示活动状态,一个是pg_locks,表示数据库的锁状态。一个是连接数挺少的,查看锁表和上锁的表,只有excluselockaccessshare模式的,excluselock只能读,但是没有针对表的,插入表的数据也正常,可简单实用这个方式测试selectt.relname,l.locktype,page ,pid,mode,granted from pg_locks l, pg_stat_all_tablest where l.relation=t.relid order by relation asc;结果如下图:wKiom1MZWuPCNmjPAACddrrUECA566.jpg

当然也可变更一个字段插入,用于测试表的状态,如插入task表:insert into task(name) select 'bb' from task limit1;

找出lock及执行的语句:selectl.pid,l.mode,sa.procpid,sa.current_query from pg_locks l inner joinpg_stat_activity sa on l.pid=sa.procpid;

Apache

转移到apache,通过httpd –s或者apache -s可以看出其工作方式是prefork模式,这种模式就会每个连接建立一个进程,通过如下的配置一路了然,最大连接数能达到150,根据ps -elf|grep :443来查看,远没达到这个数。将MaxRequestPerchild改为非0,避免内存泄漏,另外没请求的时候降低资源占用。从系统到web一层一层分析系统变卡的原因_第2张图片


系统一切正常,只能是代码的问题或者是浏览器的问题,这个时候请求用户远程协助,看到ie卡住了,firefox一切正常,不管怎么操作都是正常的,按照常理来说应该是浏览器的问题,于是将关注重点转向IE,在网上也看到不少分析IEssl状态卡的情况

于是修改apache的配置,加上对IE的适配,关闭ssl的确认连接的发送(apache配置:BrowserMatch ".*MSIE [6-9]\..*" ssl-unclean-shutdown)。重启后半天都是正常的,以为就此解决了,可是一天后用户反馈不正常了,这个时候不正常的是firefox,在网上也没搜到相关理论,反正不管是firefox还是IE,不管怎么改,总有一个浏览器是卡死状态的,后来无意中看到用户还有搜狗浏览器,也启动起,重启服务后观察,这个时候搜狗也卡住了,我就怀疑不是浏览器的关系,于是转向代码。

查看访问日志,发现有分布式的请求和状态栏的请求,为了分析方便,于是去掉了分布式连接,发现这些请求还有,那就只有派出iptables了,将这些请求都干掉,干掉这些请求后还有问题,于是锁定到状态栏的请求代码。

无意之中,看到请求的代码都变成了对下图中红色的请求。从系统到web一层一层分析系统变卡的原因_第3张图片于是查看那块的代码,这个周期性的请求是每隔30s发送一次的,并且是累积的,第一次请求是获取系统状态和升级包状态,后面的则是只请求系统状态,与网络无关,到了120次之后再请求一次系统状态和升级包。但是用户的网络环境比较复杂,导致请求升级包程序总不能正常结束,这样计数器就没有增加还一直在第一次,如此就进入了一个死循环,再加上js解析引擎处理的单线程特性,导致其他请求被阻塞或者很久才能得到相应。在失败和异常下都加上计数器,避免进入死循环,另外setInterval改为setTimeout,这样只有请求结束了才会有下一次请求,不会导致请求累积效应。具体相关函数如下:


下图是ajax的处理请求的过程:


从系统到web一层一层分析系统变卡的原因_第4张图片

比较代码如下:就是在异常和失败情况下都给times计数器加一,避免进入死循环,另外就是setInterval改成setTimeout

从系统到web一层一层分析系统变卡的原因_第5张图片


总结:

1,学会分离问题,将这些纠缠在一起的问题分离开来,一个一个突破,比如说分离系统,apachepostgresql的影响,比如说分离分布式和周期性状态栏请求。只从一个地方入手,这样才能轻车上阵。

2,对于依赖延时来处理的逻辑一定要小心,很多时候不是预期,比如说遇到网络延时,遇到系统资源瓶颈都会出现在意想不到的问题。


参考链接:

http://my.oschina.net/leejun2005/blog/157910

http://blogs.msdn.com/b/ieinternals/archive/2010/04/21/internet-explorer-may-bypass-cache-for-cross-domain-https-content.aspx