Lnmp 解决 nginx 502 bad gateway

前言描述

最近网站正常使用中经常遇到 502 的 HTTP 返回状态码的报错,

首先跑去百度了一下这个问题,搜到的信息量着实庞大,看来这个问题出现的屏率相当之多,百度到的解决办法(老实讲,百度出来的解决办法虽然多,但大多数都是在相互重复,所以我几乎把百度的方法都式完,然而并没有什么效果)无奈之下只好自己找原因并解决了,这里先来介绍下我的网站环境

“502 bad gateway”在这光秃秃的白色页面上就会显示出这样的信息,犹如遥远的的雪地上,闪起了一道亮光,这光就在那里闪耀~,仿佛看到儿时的我在夕阳下的奔跑,想远了~,^_^|||     ,身为网站管理者的我看到这个拙不是令我很头疼,然后当然要找方法来解决这个“502” ,不过奇怪的是只有刷新 php-fpm 服务就没问题了

 

我的网站运行环境

服务器 平台 系统 粘连语言  网站系统
类型 阿里云ECS基础型 LNMP CentOS PHP WordPress
版本 1核1G 1M带宽 nginx 1.10.2 6.8 5.6+ 4.9+

Nginx 502 bad gateway 错误原因搜集

先跑去看了一眼百度百科,(频率这么高的问题百度应该有伐~)还是百科到了,给的解释是这样:“NGINX 502 Bad Gateway错误出现的原因较多,对于后端连接PHP服务的场景下,常见的原因有php服务响应超时,php进程不足等引起的一类服务器错误。” 解释完虽然不太明确问题到底在哪里,不过大致可以确定问题处在 PHP 身上,因为在整体网站使用中,PHP 这个角色会在用户和 WEB 服务之间来建立链接,那么如果 PHP 出来问题(超时或者死掉)那么后端的 Nginx 服务报 “bad gateway” 也就大致明白怎么会是了,(报错内容大致说网关失败,找不到出去的路)

锁定问题在 PHP

在通过不断的排查于思考,大致确可能是因为这两个原因

  • PHP FastCGI进程数量不够~

即使你的 Nginx 支持10000个进程连接,然而 PHP 只开启50个连接的话,如果访问 html 的静态页面,10000个连接没问题,但是我们的 wordpress 肯定是 php 的,那么 php 的页面最多 50 个链接,再多就会各种花式报错,比如 502 bad gateway

  • PHP FastCGI内存大小不够~

据说一个php进程空闲时占1M 负载是占20-50M,通过我的观察发现我的 php 几乎没有闲过,所以通常一个进程占50M+,(我的内存只有1G,其他服务用完大约700-800M左右)当内存被占满占之后,就好比各位正在打游戏突然内存爆满,cpu温度99°C,然后,就没有然后了吧~

确定问题原因,内存不足,PHP服务僵死

在查阅了nginx,php-fpm,mysql,messages,kernel等等的服务日志之后,发现只要页面一弹 502 ,messages 的日志里有这样一段信息:

May  4 14:57:48 zhzy kernel: [11589]   498 11589    98683    21778   0       0             0 php-fpm
May  4 14:57:48 zhzy kernel: [11590]   498 11590    98683    21727   0       0             0 php-fpm
May  4 14:57:48 zhzy kernel: [11591]   498 11591    78228     1062   0       0             0 php-fpm
May  4 14:57:48 zhzy kernel: Out of memory: Kill process 11447 (php-fpm) score 94 or sacrifice child
May  4 14:57:48 zhzy kernel: Killed process 11447, UID 498, (php-fpm) total-vm:403468kB, anon-rss:94288kB, file-rss:1524kB

这里就看的很很很明白了,内存不足并溢出,内核要杀掉某些服务来腾出内存空间,于是选择杀死了php-fpm 这个服务,(这里如果用 service php-fpm status 看服务的状态,仍然是开启的,但日志既然出来,确实被kill掉了,所有称之为“僵死”),那么也明白了,php跪了,所以 Nginx 给我们亲切的 502 bad gateway 的报错~

而且我的 php 在建立连接后即使这个连接不再使用,也会很长很长时间后才会关掉一部分,这就造成只有在某个时间点访问量大,php连接越来越多,然后内存溢出,报错~,不过只要刷新 php-fpm 服务就可以清除掉不用的连接

各位看到这里应该已经很清楚问题处在哪里了吧~

解决因内存不足引发的报错

怎么解决?…升级服务器不就好了,内存调到 8G 总不会总不溢出了伐~ ,太贵,拒绝……

那身为半个程序员的我,当然记得那句话:“程序员最大的乐趣就是压榨机器的性能~” 某位古老的智者留下的话

  • 通过Shell脚本解决内存溢出

#!/bin/sh
PHPMEM=$(free -m | head -2 | tail -1 | awk '{print $4}')
if [ $PHPMEM -lt 400 ]
then
        echo /etc/init.d/php-fpm restart
else
        exit 0
fi

这个脚本我配合 crontab 计划任务,每分钟执行一遍,内容呢,就是讲如果内存小于400的话就刷新 php-fpm 服务,通俗的讲,如果内存块满了,就通过刷新服务来关掉不需要的进程,从而腾出足够的内存空间,从而保住 php-fpm 的性命,那在这之后 nginx 502 的报错就几乎没有出现过了~

  • 通过增加SWAP内存来防止内存溢出

看到这个标题以为我要升级服务器~,呵呵不可能的,Linux 毕竟还是很强大,这里条件可以的话(有足够的分区),你也可以通过扩大SWAP交换分区来扩展内存,从而防止溢出,最终目的都是一样的

如果是 PHP 进程不够

这种情况的话只需要修改 php-fpm 的配置文件就可以了,不过这里还是要说明一下,php的进程分为静态(static)和动态(dynamic)两种,我们直接看两个示例

  • 静态(static) PHP 进程配置

[root@zhzy ~]# vim /etc/php-fpm.d/www.conf
pm = static
pm.children = 70
pm.start_servers = 10
pm.min_spare_servers = 7
pm.max_spare_servers = 100
pm.max_requests = 100

pm = static     #使用静态的处理模式,及一个固定的连接数
pm.children = 100     #静态模下开启的连接进程数量,这里是70,如果跟我的阿里服务器类似推荐<=50即可
pm.start_servers = 10     #动态模式下初始开启的进程数量
pm.min_spare_servers = 7     #动态模式下最下的进程数量,比如空闲时~
pm.max_spare_servers = 100      #动态模式下最大的进程数量,服务器发疯时~
pm.max_requests = 100     #解释起来比较麻烦,看这里吧 http://www.jincon.com/archives/180/

  • 动态(dynamic) PHP 进程配置

[root@zhzy ~]# vim /etc/php-fpm.d/www.conf
pm = dynamic
pm.children = 70
pm.start_servers = 10
pm.min_spare_servers = 7
pm.max_spare_servers = 100
pm.max_requests = 100

pm = dynamic     #使用动态的处理模式,服务器自己判断所需的进程数量
pm.children = 100     #这行此时不会生效,因为模式是动态
pm.start_servers = 10     #动态模式下初始开启的进程数量
pm.min_spare_servers = 7     #动态模式下最下的进程数量,比如空闲时~
pm.max_spare_servers = 100      #动态模式下最大的进程数量,服务器发疯时~
pm.max_requests = 100     #看这里吧 http://www.jincon.com/archives/180/

到这里通过合理的调整,只要使服务器有足够的进程来供用户使用,也就不会出现 502 bad gateway 的问题了

这篇文章对您有帮助一定要留个言哇~

1 Comment

  1. bt110 2018年5月23日 at 上午11:01

    谢谢博主热心分享,留言支持一下,也欢迎回访一下我的网站




    1



    0

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注