php项目,cpu暴增问题查找

背景:

前几天通过WordPress上线一个应用(前后台部署分离,后台走内网内部使用,前台做了全站缓存对外使用)。

今天访问后台应用发现开始报504,一段时间后全部504.

 

解决方案:

登录容器发现容器内nginx日志全部499。

通过top指令发现php-fpm占用cpu暴增。

netstat -anp|grep 'php-fpm端口号'  发现所有php-fpm状态都为syn_recv(服务端被动打开后,接收到了客户端的SYN并且发送了ACK时的状态)

所有php-fpm状态都为syn_recv,导致控制SYNqueue的队列数量满,所有新的请求直接拒绝。

立马通过strace命令进行追踪pid,发现一直在循环执行gettimeofday等一些函数

网上查找资料说如果开启xdebug扩展会引发这样的状况,通过php -m发现果然使用了xdebug,关闭此扩展,重启php-fpm。

进行观察发现,cpu使用率平稳,php-fpm状态正常,一切正常。

 

总结:

线上不要开启xdebug扩展,为什么xdebug会引起此种问题,暂时未深入了解,但是xdebug性能低不适合线上使用,建议使用php_trace扩展代替

通过php_trace来检测php代码执行流程,关于怎样使用php_trace,可查看之前所写的文章。(php_trace为360开源的工具,性能强大,经他们测试在线上只会损耗百分之几左右的性能)

开启php-fpm状态监控,最好能增加报警机制,已及时发现与获取问题原因。

 

 

解释:

这里有必要解释下, TCP连接为什么会积压在队列里, 要理解这个问题, 需要先理解linux 对TCP 三次握手的一些具体实现。

我们知道, 在server端,监听一个端口, 调用socket,bind 最后调用listen:

int listen(intsockfd, int backlog);

listen的第二个参数叫做backlog, 用来设置连接队列的大小。实际Linux 维护两个队列, 一个是在接收到SYN后,此时没有完成三次握手, 处于半连接状态,存放到SYNqueue(我们的问题就是发生在此处),

另一个是三次握手完成后, 成功建立连接,存放到acceptqueue,等待应用调用accept 来消费队列。这里的backlog就是用来设置accept queue(旧版内核用来设置SYN queue,详细请man listen)的大小。

TCP 传输跟系统调用实际是一个异步的过程, 系统通过队列来保存最新的TCP状态或数据。也就是说,TCP三次握手由内核来完成, 跟应用层是否调用accept无关, 内核将完成三次握手的socket 放到acceptqueue中,应用调用accept 时,从accept queue中获取连接。那么,如果backlog 非常大,而我又不及时调用accept 来消费队列,则连接就被积压到accept queue中了。

同样, 在三次握手完成后, 客户端就可以发送数据了, 数据由内核接收, 并保存在TCP 的buffer中, 而此时应用(PHP)可能还没有调用accept。

 

最后感谢一下曾经的面试官,因为之前有问到如何查找线上cpu暴增问题,后来查找了下基本资料,没想到这次用到了。。

 

posted on 2017-03-22 17:59  面壁偷笑  阅读(473)  评论(0编辑  收藏  举报