一次线上问题,让我意识到,fpm 居然是用这种方式处理超时的,虽然有点震惊,但是想想,这才是我大 PHP 处理问题的方式,简单粗暴而且高效。
问题的现象是这样的,某个接口访问量大增,然后接口大量502,接着 fpm 的机器cpu暴涨,最后gg。
fpm 处理超时的方式非常简单,那就是,直接退出 worker 子进程。
对于超时的处理,fpm 的代码里是这样写的的(我隐去了细节,有兴趣的可以去 PHP 官网下载一份源码看看,在源码的 sapi/fpm 目录里) 检测超时
static void fpm_pctl_check_request_timeout(struct timeval *now)
{
……
fpm_request_check_timed_out(child, now, terminate_timeout, slowlog_timeout);
……
}
处理超时
void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, int terminate_timeout, int slowlog_timeout)
{
……
fpm_pctl_kill(child->pid, FPM_PCTL_TERM);
……
}
}
然后kill
int fpm_pctl_kill(pid_t pid, int how)
{
……
return kill(pid, s);
}
然后问题就清楚了,接口里有个服务超时,造成fpm超时,fpm worker 进程不断被kill掉并拉起新的 fpm worker 进程,然后不断的这样 kill 然后拉起,cpu 就暴涨,最后 gg。
这个问题怎么避免,去掉 fpm 超时是万万不可取的,只能严格控制代码,调用每一个外部服务必须设置超时时间,而且这个超时时间必须小于 fpm 超时时间。
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师