08.17 php-fpm负载飙升解决实战

还记得那年拉手网wap服务器(m.lashou.com)发生过一次莫名其妙的服务器负载飙升事件(那时的业务量也比较大),以前大体记录了解决过程,现在再整理下为遇到此种问题的人提供下思路,同时也是对相关知识的巩固。

从10.10下午五点半多wap相关服务器(m.lashou.com)的负载开始飙升,load average甚至超过200,服务器撑一两个小时就宕机。从session数据库服务器来看,连接到其上的最多的就是我(朱)这边业务的服务器,登录相关服务器free -m查看内存很快被吃尽进而导致服务器宕机(现在已将session数据存入redis)。由于以前也出现过类似情况,加之10号下午连接session数据库的配置文件更改(ip被换,涉及机房迁移,怀疑两个节点间的网络通道有点问题,进而引起了一系列问题),所以运维人员(运维工程师刘桥)第一反应是由此引起的并通知到我(朱)这边。但是我的判断是以前也更改过这种数据库配置文件,并没有引起这种情况,并且如果2个节点之间网络通道有问题的话,从服务器上来看对应该session数据库应该会有很多的timewait,但是根据相关命令查看并不多,截图如下:

php-fpm负载飙升解决实战

因此基本排除这种情况。13年也曾经出现过这样一次情况,会不会跟上次一样是因为服务器的tcp参数配置不够优化引起的呢。Linux系统下,TCP连接断开后会以TIME_WAIT状态保留一定的时间,然后才会释放端口。当并发请求过多的时候,就会产生大量的TIME_WAIT状态的连接,无法及时断开的话会占用大量的端口资源和服务器资源.这个时候我们可以优化TCP的内核参数,来及时将TIME_WAIT状态的端口清理掉。输入下面的组合命令,查看当前TCP连接的状态和对应的连接数量。

php-fpm负载飙升解决实战

我们只关心timewait的连接个数即可,从上图看到timewait个数也不是很多。查看相关配置文件$more /etc/sysctl.conf,确认了下

#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies处理,可防范少量SYN攻击,默认为0,表示关闭

net.ipv4.tcp_syncookies = 1

#表示开启重用。允许将timewait sockets重新用于新的TCP连接,默认为0,表示关闭

net.ipv4.tcp_tw_reuse = 1

#表示开启TCP连接中timewait sockets的快速回收,默认为0,表示关闭

net.ipv4.tcp_tw_recycle = 1

#修改系统默认的timeout时间

net.ipv4.tcp_fin_timeout = 30

配置没有问题。综上判断并不是因为网络通道/linux服务器配置参数不当引起。

由于是线上环境涉及线上业务因此建议运维工程师(刘)先写个脚本对php-fpm进行监控,如果占用内存到一定程度达到一定阈值用reload参数定时重启nginx服务器以达到重载php-fpm将业务平稳过渡的目的。先尽可能的减少对用户的伤害,然后再具体查找原因。

第二天通过查看php-fpm的状态(查看配置文件在php-fpm配置文件中)如下:

php-fpm负载飙升解决实战

访问http://主机名/ls-status1.php即可查看。

#启动日期,如果reload了php-fpm,时间会更新

start time: 16/Oct/2014:17:10:13 +0800

start since: 67275 #运行时长

可以看出大约2个小时重启一次,也就是说约2个小时内存会耗尽。

那是什么问题引起的呢?目前的现象是通过free -m检测会发现可用内存慢慢变少,直至耗尽。可用内存曲线是向下的,而不是到某个点之后再慢慢的上升。如果是java程序的话,第一反应应该是程序处理不当而引起内存泄露,但是php程序是解释型语言,运行时间会比较短,连接数据库及curl函数都设定了超时时间。况且php版本为5.3.10这个版本没有内存泄露的bug,服务器飙升之前的代码与现在一致,并没有变动,因此基本排除不是代码层面的原因。那会不会是web server的原因呢,目前用的是LNMP架构。Nginx不支持对外部程序的直接调用或者解析,必须通过fastcgi进行调用。Nginx收到cgi请求之后,fastcgi接口在脚本解析服务器上,启动一个或者多个守护进程对动态脚本进行解析,Php-fpm是一个fastcgi进程管理器/引擎(即对动态脚本进行实际解析的守护进程,由fastcgi启动)。我理解php-fpm就是一个进程池,它的配置文件配置了fastcgi具体运行的方式。如果配置不当,fastcgi一直开启进程而不释放,就会造成进程堆积引起内存溢出,进而引起服务器宕机。

通过命令ps -ylC php-fpm --sort:rss 查看一个php-fpm进程占用的实际内存空间平均为20多M(下面截图只列出了一部分)

php-fpm负载飙升解决实战

php-fpm负载飙升解决实战

抓紧检查下php-fpm配置文件,咦?发现pm.max_requests(发送多少个请求后会重启该线程,从而使其释放占用的内存,默认0即决不重启一直接受请求)的值为0。

通过cat /proc/meminfo 查看m.lashou.com服务器的内存为8G,从上图sz项可以看出一个php-fpm进程能够正常运转起来占用的内存大部分为100M多,为保险起见这里预留2G内存给系统及其他应用使用。根据设置进程数原则(在N+20%和M/m之间)。

N 是 CPU 内核数量。

M 是 PHP 能利用的内存数量。

m 是每个 PHP 进程平均使用的内存数量。

所以对php-fpm做如下配置:

pm.start_servers = 24 #动态方式下的起始php-fpm进程数量

pm.min_spare_servers = 16 #动态方式下的最小php-fpm进程数量

pm.max_spare_servers = 32#动态方式下的最大php-fpm进程数量

pm.max_requests = 1024 #静态方式下开启的php-fpm进程数量

重启nginx继续观察,

php-fpm负载飙升解决实战

发现没有重启现象,检测了下内存使用情况基本平稳(在接下来的几天观察中也没发现什么异常)。

结论:算是告一段落了,通过这个事情我们可以看出配置文件也要随服务器的负载情况进行适当调整,在负载不高、比较平稳时时pm.max_requests为0不会引起什么问题,但是当负载高、并发大时问题就凸显了,就需要调整相应的参数(当时当日pv突破了1000W)。配置文件中还有一个重要参数需要注意下request_terminate_timeout

(脚本最大执行时间)目前设置是30S,

php-fpm负载飙升解决实战

其实最好设置10S或者更短。因为这么长时间没有响应,那应该是有程序问题,尽早断开以释放资源。


分享到:


相關文章: