上周报名了一个活动,结果对方服务器nginx 502了,有朋友进去了活动页面,我都没进得去!后来听说是php配置文件没配置好,导致了这个问题。

正好最近入了php的坑,就来学习一些php配置里面可能会导致服务器nginx 502的地方。

nginx 502 一般是以下几种情况:

  • php-fpm进程没有启动,或者nginx的fastcgi_pass设置错误,导致nginx连不到php
  • php worker进程不够,请求太多处理不过来
  • php-fpm执行超时,被kill掉,导致nginx与其连接被断开

nginx 504 一般是以下情况:

  • 虽然php脚本还在执行,但nginx与上游通信时间超时。

下面就来以此解决这几个问题:

一、 php-fpm进程或者nginx fastcgi_pass配置

确认php-fpm是否已启动,可使用命令ps aux|grep php-fpm查看进程

确认nginxfastcgi_pass是否正确:

  • 先确认php-fpm已启动
  • fastcgi_pass有两种形式
    • ip:port。(如:127.0.0.1:9000)这种方式使用TCP链接,会经过网络请求。
    • unix socket.(如:unix:/home/users/nemo/php/var/run/php-cgi.sock)这种方式不会进行网络请求,而是在内部发送系统信息。
    • 一般情况下,这两种方式都可以,性能差别不大。如果要提高一下性能,就使用unix socket的形式。如果要请求非本机的php-fpm,那么只能使用ip:port的形式。
    • 具体你的php-fpm使用的是哪种形式,可以在配置文件php-fpm.conf里面,listen属性里面查看。


二、php的worker进程不够,请求太多,处理不过来

最简单粗暴的,就是在php-fpm.conf里面增加pm.max_children的个数。

但是,这里要考虑到内存占用的问题。关于内存,有几个方面:

  • php.ini里面的memory_limit表示的是一个php-cgi进程最多占用的内存。每个请求完成后php-cgi会回收内存,但是不会释放给操作系统,这样就会导致大量内存被php-cgi占用
  • 在代码里面,可以临时设置当前脚本最大占用的内存,如ini_set('memory_limit', 20M)
  • 假如说,每个php-cgi即worker进程,占20M内存,那么5个worker的话就占100M内存。
  • 当服务器请求很多的时候,5个进程全部在处理任务,对很多只有128M的虚拟主机(vhost)来说,如果还要处理其他程序,内存很可能很吃紧。

下面就来说说,如何配置worker的个数。

pm:它有三种模式,static, dynamic, ondemand。下面来说说这三种模式的区别:

dynamic模式:php-fpm启动时,会产生固定数量(由pm.start_servers决定)的worker进程,而最大子进程数由pm.max_children决定。其中pm.max_spare_servers是最大空闲子进程数,当空闲的worker数超过pm.max_spare_servers时,就会把多余的杀掉。而pm.min_spare_servers是最小空闲子进程数,当空闲子进程小于pm.min_spare_servers,则会新增worker进程。

dynamic模式下,可能会存在一种现象,比如,高峰期过了之后,内存占用还是没有少。重启之后就少了。

举例来说:比如pm.max_children = 50pm.max_spare_servers = 35pm.min_spare_servers = 5,高峰期时,50个worker都在处理任务,高峰期过了之后,woker都闲置了,根据pm.max_spare_servers会有15个worker被杀掉,仍有35个worker进程闲置,并且占用着内存。这就是高峰期过后,内存仍然高居不下的原因。

当重启之后,根据pm.min_spare_servers会产生5个新的worker。这就是高峰期过后重启之后,内存占用显著变小的原因。

static模式:始终保持一个固定数量的woker进程,数量由pm.max_children定义。其他配置,如pm.start_servers等都用不上。

ondemand模式:该模式下,只有pm.max_childrenpm.process_idle_timeout有用。php-fpm启动的时候,只会创建master,不会创建worker。当请求来的时候,再创建worker,pm.max_children决定最大worker进程数。而pm.process_idle_timeout决定闲置进程在持续闲置了多少秒之后就会被杀掉。

ondemand模式下,如果高峰期请求非常大,那么就会频繁地创建worker进程,产生很多不必要的消耗。如果长时间没请求,那么就只会有一个php-fpm主进程

一般默认的模式是dynamic,具体采用什么模式,使用什么配置,还需要根据自己的机器来设定。

本文一开始说的因php配置产生nginx 502的问题,应该就是当请求量很大,又没有内存生成新的worker的时候,会产生nginx 502问题。

还有一个参数pm.max_requests,与worker进程个数无关,但也可能引起nginx 502。pm.max_requests表示每个子进程重生之前处理的请求数,对于可能存在内存泄漏的第三方模块来说非常有用。如果设置为 '0' 则表示一直接受请求。等同于 PHP_FCGI_MAX_REQUESTS 环境变量。当某些php模块存在内存泄露,导致内存占用很高时,无法再处理新的请求,就会nginx 502。


三、php-fpm执行超时

php-fpm.conf里面有参数request_terminate_timeout,这个参数设置的是fastcgi花费的所有时间。如果超过了这个时间,那么就会将php-fpm kill掉,并返回502 Bad Gateway。默认这个参数是0,表示不设置超时时间。

php.ini里面的max_execution_time设置了每个脚本最多执行的时间(单位是 ),这里仅仅指代码本身执行的之间,不包括网络请求、数据库查询、系统调用、sleep等。默认这个值是30s,如果超过这个时间,会产生Fatal: Maximun execution time错误,会返回500 Internal Server Error

nginx 里面也有超时配置:

  • fastcgi_connect_timeout。nginx和fastcgi建立连接的超时时间。
  • fastcgi_read_timeout。nginx与fastcgi建立连接之后,获得响应的超时时间。若请求需处理的业务逻辑比较复杂,或者在数据里里面查询大量数据,则很可能会在此处超时。返回502 Bad Gateway
  • fastcgi_send_timeout。nginx向fastcgi发送请求的超时时间。如果超过这个时间,没有发送完请求,就会断开连接。比如说上传大文件的时候,超时,会返回504 Gateway time-out

上面说到了几个可能会引起502 、504的原因,主要是内存占用过高或者超时。关于内存占用,可以使用free命令来查看。

下面这张图是centos 7上的free命令

关于可用内存的计算,centos7 与低版本不一样。

centos 7里面,available只的是 free + buffers/cache - 不可回收的共享部分。以前available指的是 free + buffers/cache

如果看到内存占用高,可以使用top命令查看当前有多少进程、有多少在运行、内存占用高的进程分布


一般情况下,php源码安装,一般使用--with-config-file-path设置配置文件的路径,但是源码安装完之后很可能没有php.ini,需要自己去源码包里面拷贝php.ini-developmentphp.ini-production过来。

上面说到一些php.ini里面的配置,如果要使用php cli指定某个特定的php.ini而不是默认的,那么可以使用-c选项。

举例:

php -c /home/user/nemo/testphp/php.ini index.php