起因
每周五一般都是一个流量相对密集的时刻,所以当流量比以往高的时候,问题就相应出现了。接到报警,系统load值飙高 ,load值200多,cpu使用率100% , cpu sys 70% , cpu sys 30% 。请求耗时描述秒级以上。内存使用正常。
快速应急处理
因为是个周五晚上,都刚到家里,只能用临时处理方案,看看能不能快速解决问题。
1. 重启服务,第一个想到最快的解决办法,看看重启是否有效。其结果,cpu和负载下来了。没过多久,就又回到了起点。cpu load值很快又上去了,所以重启服务没有缓解问题。
2. 扩容增配 发现重启无效之后,因为这个服务是一个轻量型的一个小微服务,所以当时选择了个低配的机子,4核8g内存。那最快能缓解的办法就是扩容增配。因为我们是云服务,扩容和增配还是相对简单快速的。
相比之下,我们先增配,成本最低,来的更快。然后将机器配置升到8核16g,然后作了一次扩容。升配之后是有比较明显的效果,cpu也下来,不再是100%,load值也下来了,但是cpu使用率也还是不低。因为升级成8核,所以没有明显的处理不过来的现象。
问题排查
等到服务稳定一些,我们要找到问题到底出在哪里。
一个比较简单的逻辑操作,为什么会有这么大的耗时,和这么高的cpu
随后我就对我们的服务进程进行监控。
看看到底问题到底出在哪里
首先因为升配了,看看升配之后我们的服务到底能有多少的qps吧。
压测的结果很令人揪心啊
结果不堪入目
简单压测下来,要分析一下,究竟问题出在了哪里
strace -c -p 728
发现99%的耗时,系统都消耗在clone上。
clone? 程序中到底干了什么,我没有fork进程啊,为什么要clone一个进程出来
那么看看到底都干了什么吧
strace -p 6371
一次请求要作两次clone,要fork两个进程出来工作。
然后fork 出来的进程作了一个read 读了一个ip出来。
经过排查代码发现,我们代码中,有一段是要获取本地ip
用了一个这样的方法
exec( “…” );
执行了一个php 的 exec的操作去拿本地服务ip,这个命令导致了系统会fork进程,去处理exec 执行的外部命令.
所以看进程的strace就能看到 系统内核执行的两次clone是由于php用了两次exec导致的。
原因找到了,因为系统fork进程开销很大,也很耗时,所以导致我们的服务qps 效率低下,cpu高也是因为cpu一直在作创建进程,设置进程通信的事。所以,我们就把这两次exec执行的语句去掉,换了另一种不需要执行exec的操作的方法替换。
再次压测的结果
效果非常明显,这样的结果才是我们预期的。问题找到了,赶紧修复上线吧,然后观察一下线上的服务如何。
请求耗时迅速降了一个等级
cpu使用率也立马见效了。
最后总结一下,线上的服务一定要慎用一些 函数如
exec system passthru
如果需要的话可以试试
pcntl_exec
然后排查问题的时候要找到问题重点再去排查问题;
推荐几个命令在排查性能问题比较实用,strace , gdb 能帮助你很快找到问题方向,然后再去排查代码问题。