前言描述
最近网站正常使用中经常遇到 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 总不会总不溢出了伐~ ,太贵,拒绝……
那身为半个程序员的我,当然记得那句话:“程序员最大的乐趣就是压榨机器的性能~” 某位古老的智者留下的话
这个脚本我配合 crontab 计划任务,每分钟执行一遍,内容呢,就是讲如果内存小于400的话就刷新 php-fpm 服务,通俗的讲,如果内存块满了,就通过刷新服务来关掉不需要的进程,从而腾出足够的内存空间,从而保住 php-fpm 的性命,那在这之后 nginx 502 的报错就几乎没有出现过了~
通过增加SWAP内存来防止内存溢出
看到这个标题以为我要升级服务器~,呵呵不可能的,Linux 毕竟还是很强大,这里条件可以的话(有足够的分区),你也可以通过扩大SWAP交换分区来扩展内存,从而防止溢出,最终目的都是一样的
如果是 PHP 进程不够
这种情况的话只需要修改 php-fpm 的配置文件就可以了,不过这里还是要说明一下,php的进程分为静态(static)和动态(dynamic)两种,我们直接看两个示例