一条502报警引起的胡思乱想

安心倒计时

忙完了今天的工做, 终于到了周五,能够好好休息下了。php

睡梦惊醒

就在安心养神的时候, 同事转给了我一条nginx 502的报警, 赶忙去线上一顿排查。nginx

首先得先找出哪台机器报出的(同时喊运维看下线上负载状况), 发现01机器的nginx日志在报警时间点的错误信息:数据库

*272881176 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: xx.xx.xx.xx, server: , request: "POST /xxx/xxx HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "xx.xx.xx.xx:8081"centos

recv()为接收返回数据的系统函数,基本能够先认为报错缘由为bash

Nginx发现某服务与本身通讯的链接断掉了,就会返回给客户端502错误。服务器

那么nginx是从哪里接收数据呢,报错信息一样很明显,fastcgi://127.0.0.1:9000markdown

思考原因

一样思考为何php的处理进程会中断呢?运维

  1. 莫非执行任务超时,fpm主动杀死?
  2. 又莫非系统资源不足,系统杀死

一样针对这两种状况,排查结果:socket

  1. 报警的此接口并非特别复杂的接口,执行时间也并不长,之前也并未出现过问题
  2. 经过zabbix、埋点监控、系统负载查看,cpu、内存、fpm总体进程状况也比较正常

顺便也看了下 fpm的错误日志、慢日志,也没有什么收获(此处极可能会忽略掉了重要信息)tcp

蛛丝马迹

因而既然认为是fpm出了问题,就调研下fpm的配置文件吧

pid = /usr/local/var/run/php-fpm.pid
#pid设置,必定要开启,上面是Mac平台的。默认在php安装目录中的var/run/php-fpm.pid。好比centos的在: /usr/local/php/var/run/php-fpm.pid
error_log  = /usr/local/var/log/php-fpm.log
#错误日志,上面是Mac平台的,默认在php安装目录中的var/log/php-fpm.log,好比centos的在: /usr/local/php/var/log/php-fpm.log
log_level = notice
#错误级别. 上面的php-fpm.log纪录的登记。可用级别为: alert(必须当即处理), error(错误状况), warning(警告状况), notice(通常重要信息), debug(调试信息). 默认: notice.
emergency_restart_threshold = 60
emergency_restart_interval = 60s
#表示在emergency_restart_interval所设值内出现SIGSEGV或者SIGBUS错误的php-cgi进程数若是超过 emergency_restart_threshold个,php-fpm就会优雅重启。这两个选项通常保持默认值。0 表示 '关闭该功能'. 默认值: 0 (关闭).
process_control_timeout = 0
#设置子进程接受主进程复用信号的超时时间. 可用单位: s(秒), m(分), h(小时), 或者 d(天) 默认单位: s(秒). 默认值: 0.
daemonize = yes
#后台执行fpm,默认值为yes,若是为了调试能够改成no。在FPM中,可使用不一样的设置来运行多个进程池。 这些设置能够针对每一个进程池单独设置。
listen = 127.0.0.1:9000
#fpm监听端口,即nginx中php处理的地址,通常默认值便可。可用格式为: 'ip:port', 'port', '/path/to/unix/socket'. 每一个进程池都须要设置。若是nginx和php在不一样的机器上,分布式处理,就设置ip这里就能够了。
listen.backlog = -1
#backlog数,设置 listen 的半链接队列长度,-1表示无限制,由操做系统决定,此行注释掉就行。backlog含义参考:http://www.3gyou.cc/?p=41
listen.allowed_clients = 127.0.0.1
#容许访问FastCGI进程的IP白名单,设置any为不限制IP,若是要设置其余主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每一个地址是用逗号分隔. 若是没有设置或者为空,则容许任何服务器请求链接。
listen.owner = www
listen.group = www
listen.mode = 0666
#unix socket设置选项,若是使用tcp方式访问,这里注释便可。
user = www
group = www
#启动进程的用户和用户组,FPM 进程运行的Unix用户, 必需要设置。用户组,若是没有设置,则默认用户的组被使用。
pm = dynamic 
#php-fpm进程启动模式,pm能够设置为static和dynamic和ondemand
#若是选择static,则进程数就数固定的,由pm.max_children指定固定的子进程数。
#若是选择dynamic,则进程数是动态变化的,由如下参数决定:
pm.max_children = 50 #子进程最大数
pm.start_servers = 2 #启动时的进程数,默认值为: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
pm.min_spare_servers = 1 #保证空闲进程数最小值,若是空闲进程小于此值,则建立新的子进程
pm.max_spare_servers = 3 #,保证空闲进程数最大值,若是空闲进程大于此值,此进行清理
pm.max_requests = 10000
#设置每一个子进程重生以前服务的请求数. 对于可能存在内存泄漏的第三方模块来讲是很是有用的. 若是设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.
pm.status_path = /status
#FPM状态页面的网址. 若是没有设置, 则没法访问状态页面. 默认值: none. munin监控会使用到
ping.path = /ping
#FPM监控页面的ping网址. 若是没有设置, 则没法访问ping页面. 该页面用于外部检测FPM是否存活而且能够响应请求. 请注意必须以斜线开头 (/)。
ping.response = pong
#用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.
access.log = log/$pool.access.log
#每个请求的访问日志,默认是关闭的。
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
#设定访问日志的格式。
slowlog = log/$pool.log.slow
#慢请求的记录日志,配合request_slowlog_timeout使用,默认关闭
request_slowlog_timeout = 10s
#当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 '0' 表示 'Off'
request_terminate_timeout = 0
#设置单个请求的超时停止时间. 该选项可能会对php.ini设置中的'max_execution_time'由于某些特殊缘由没有停止运行的脚本有用. 设置为 '0' 表示 'Off'.当常常出现502错误时能够尝试更改此选项。
rlimit_files = 1024
#设置文件打开描述符的rlimit限制. 默认值: 系统定义值默承认打开句柄是1024,可以使用 ulimit -n查看,ulimit -n 2048修改。
rlimit_core = 0
#设置核心rlimit最大限制值. 可用值: 'unlimited' 、0或者正整数. 默认值: 系统定义值.
chroot =
#启动时的Chroot目录. 所定义的目录须要是绝对路径. 若是没有设置, 则chroot不被使用.
chdir =
#设置启动目录,启动时会自动Chdir到该目录. 所定义的目录须要是绝对路径. 默认值: 当前目录,或者/目录(chroot时)
catch_workers_output = yes
#重定向运行过程当中的stdout和stderr到主要的错误日志文件中. 若是没有设置, stdout 和 stderr 将会根据FastCGI的规则被重定向到 /dev/null . 默认值: 空.
复制代码

摘自 www.zybuluo.com/phper/note/…

单独拿出几个重要配置项:

pm = static
#php-fpm进程启动模式,pm能够设置为static和dynamic和ondemand
#若是选择static,则进程数就数固定的,由pm.max_children指定固定的子进程数。

pm.max_children = 500 #子进程最大数

request_terminate_timeout=30
#设置单个请求的超时停止时间. 该选项可能会对php.ini设置中的'max_execution_time'由于某些特殊缘由没有停止运行的脚本有用. 设置为 '0' 表示 'Off'.当常常出现502错误时能够尝试更改此选项。

request_slowlog_timeout=3
#当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 '0' 表示 'Off'

pm.max_requests=10000
#设置每一个子进程重生以前服务的请求数. 对于可能存在内存泄漏的第三方模块来讲是很是有用的. 若是设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.
复制代码

开始学习

以上即是咱们线上的主要配置,主要仍是集中在了 request_terminate_timeout 这个参数上。它和php.ini的 max_execution_time 有什么区别

set_time_limit()函数和配置指令max_execution_time只影响脚本自己执行的时间。任何发生在诸如使用system()的系统调用,流操做,数据库操做等的脚本执行的最大时间不包括其中,而 request_terminate_timeout 是包含全部时间的

php.ini配置时间一样也为30,可是相比而言,request_terminate_timeout时间会更短。

回归正题

但前文咱们明明说了,这个接口并非很复杂啊。..应该不会超时啊,当时第三方服务也没有什么异常状况,fpm错误日志也并无这个超时错误信息。各个依赖的系统负载都还处于比较低峰期状态

在疑问中结束了今天的工做,回来打算写一下分享今天的调试经历,在搜索文档的时候又发现了这么一句话:

复制别人文章

Nginx 502 Bad Gateway错误

在php.ini和php-fpm.conf中分别有这样两个配置项:max_execution_time和request_terminate_timeout。

这两项都是用来配置一个PHP脚本的最大执行时间的。当超过这个时间时,PHP-FPM不仅会终止脚本的执行,

还会终止执行脚本的Worker进程。因此Nginx会发现与本身通讯的链接断掉了,就会返回给客户端502错误。

以PHP-FPM的request_terminate_timeout=30秒时为例,报502 Bad Gateway错误的具体信息以下:

1)Nginx错误访问日志:

2013/09/19 01:09:00 [error] 27600#0: *78887 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 192.168.1.101, server: test.com, request: "POST /index.php HTTP/1.1", upstream: "fastcgi://unix:/dev/shm/php-fcgi.sock:", host: "test.com", referrer: "test.com/index.php"

2)PHP-FPM报错日志:

WARNING:  child 25708 exited on signal 15 (SIGTERM) after 21008.883410 seconds from start
复制代码

因此只需将这两项的值调大一些就可让PHP脚本不会由于执行时间长而被终止了。

request_terminate_timeout能够覆盖max_execution_time,因此若是不想改全局的php.ini,那只改PHP-FPM的配置就能够了。

此外要注意的是Nginx的upstream模块中的max_fail和fail_timeout两项。有时Nginx与上游服务器(如Tomcat、FastCGI)的通讯只是偶然断掉了,但max_fail若是设置的比较小的话,那么在接下来的fail_timeout时间内,Nginx都会认为上游服务器挂掉了,都会返回502错误。因此能够将max_fail调大一些,将fail_timeout调小一些。

摘自最棒的51cto: blog.51cto.com/nanchunle/1…

自圆其说

对于nginx的upstream模块并非很了解,回忆当时报错场景,确实发现日志里面先后报了几个不一样接口一样的错误,也多是其余接口影响了此接口,只是它正好被报警系统抓取到。

反思

思考问题可能过于片面,没有解决问题的一套体系、思路,容易绕弯路、甚至南辕北辙。

结论

这是一篇没有结论的文章.

后续会尝试复现此场景,但愿你们持续关注。

欢迎关注 < 呆呆熊一点通 >

相关文章
相关标签/搜索