网站突然502了,老板在群里@你,怎么办?

咖啡刚喝一口,手机就震得像要跳桌。
群消息99+,监控红得刺眼,首页赫然挂着“502 Bad Gateway”——不是幻觉,是真的挂了。

别点刷新,先深呼吸。502不是服务器炸了,是中间人卡住了。按下面这几步走,10分钟内大概率能拉回来。

502错误到底是什么?先看懂再动手

502 是 HTTP 状态码,意思是“网关收不到后端的回音”。

它不等于你的网站代码崩了,也不等于数据库死了。而是 Nginx、CDN 或负载均衡器这类“传话员”,去敲你后端服务(比如 PHP-FPM、Java 应用)的门,结果没人应、门不开、或者等半天才慢吞吞递出一张废纸。

常见“传话员”:Nginx(最常见)、Apache 反向代理模式、Cloudflare、阿里云 SLB。

一个真实案例:客户一见502就狂重启 PHP,反复三次没用。最后翻 Nginx 错误日志,发现 proxy_pass http://192.168.1.100:8080 —— 后端 IP 写错了,压根连不到“餐厅”。改对地址,秒恢复。

第一步:5分钟内必须做的紧急检查清单

别开浏览器刷页面,直接上终端。打开两个 SSH 窗口,一个盯日志,一个跑命令。

  1. 后端服务还在跑吗?
    systemctl status php-fpm(PHP 站)
    systemctl status tomcat(Java 站)
    ps aux | grep gunicorn(Python 站)
    看一眼状态是不是 active (running),如果不是,先 systemctl start xxx

  2. 立刻看 Nginx 错误日志
    tail -f /var/log/nginx/error.log
    别滑屏,盯着最新几行。关键词:“connect() failed”、“upstream timed out”、“no live upstreams”——这些就是破案线索。

  3. 服务器是不是被榨干了?
    tophtop 快速扫一眼:CPU 长期 95%+?内存只剩几百 MB?MySQL 连接数飙到 max_connections?资源见底,请求自然排队超时。

关键动作:一边 tail -f error.log,一边敲 systemctl status php-fpm。日志里报哪一行错,你就去查对应的服务或配置。

第二步:根据错误日志,精准打击问题根源

日志不是天书,这几类报错,对应几类解法:

看到 “Connection refused to upstream”
→ 网关根本连不上后端。
可能:PHP-FPM 崩了、端口监听错了(比如配置写 8080,实际只开了 9000)、防火墙临时拦了内网通信。
马上做systemctl restart php-fpm;检查 listen = 127.0.0.1:9000 和 Nginx 里的 proxy_pass 是否一致;iptables -L 看有无新规则。

看到 “upstream timed out”
→ 网关连上了,但后端卡住不给回应。
可能:某个 PHP 脚本死循环、数据库查询堵死、调第三方 API 一直 hang 住。
马上做pstack $(pgrep php-fpm) 看进程在卡哪行;临时注释掉最近上线的功能模块;重启 PHP-FPM 清理积压。

一个具体场景:日志满屏“upstream timed out”,查进程发现一堆 PHP 在等地图 API 返回。把那段调用临时注释掉,reload Nginx,流量立刻回流。

第三招:这些配置陷阱,你可能一直没注意

平时风平浪静,一到大促或爬虫扫过来,就原形毕露。

PHP-FPM 子进程不够用
pm.max_children 设太小(比如默认 5),10 个用户同时访问,第 6 个就得排队。排太久,Nginx 就甩出 502。
改法:按服务器内存算,每个 PHP 进程约占 30–80MB,留一半内存给系统,剩下除一下,填进 pm.max_children

Nginx 超时时间太短
proxy_read_timeout 60; 是默认值。但生成一份订单报表要 90 秒?Nginx 等不及,直接断连返 502。
改法:在对应 location 块里加 proxy_read_timeout 120;,别全局改,只针对耗时接口。

缓冲区小到装不下响应头
后端返回的 Set-Cookie 太长,或响应体带大 Base64 图片,超出 proxy_buffer_size 4k,也会触发 502。
改法proxy_buffer_size 16k; proxy_buffers 8 16k;

第四招:当数据库成为“拖后腿”的元凶

502 报警响了,别光盯着 PHP。后端服务卡住,八成是被数据库拖死的。

快速诊断(MySQL)
mysql -u root -pSHOW PROCESSLIST;
重点找 StateSending dataLockedCopying to tmp tableTime 超过 30 秒的行。记下 Id,直接 KILL 12345; 干掉它。

后续必须做

  • 开启慢查询日志:slow_query_log = ONlong_query_time = 2
  • 对搜索字段加索引,尤其避免 LIKE '%关键词%' 全表扫描
  • 电商站曾因商品搜索没索引,在 50 万数据上全表扫,导致 PHP 进程集体卡死,502 频发。加完索引,问题消失。

第五招:预防大于治疗,如何让502不再复发

救火一次是本事,不着火才是真功夫。

  1. 服务自动复活:用 systemdRestart=always,或 Supervisor 监控 PHP-FPM,崩了自动拉起。
  2. 资源提前预警:在你常用的监控面板(比如 Zabbix、Prometheus + Grafana、甚至宝塔后台)里,给 CPU、内存、MySQL 连接数设报警线,超 80% 就微信/钉钉告警。
  3. 上线前压一压:用 ab -n 1000 -c 100 https://yoursite.com/ 模拟并发,看 PHP-FPM 进程数和响应时间是否稳定。
  4. 外部依赖要兜底:调微信登录、短信接口,加 try/catch + 默认返回,别让它卡住整个下单流程。

今天下班前就能做的“502防火墙”行动

别等下次报警。现在就打开终端,花 5 分钟加固:

  1. 执行 sudo nano /etc/php/{版本号}/fpm/pool.d/www.conf(Ubuntu/Debian)或 /usr/local/php/etc/php-fpm.d/www.conf(编译安装)
  2. 找到 pm.max_children,改成你算出来的安全值(例如:4G 内存服务器,设为 20
  3. 找到 request_terminate_timeout,设为 300(单位秒),确保它 > Nginx 的 proxy_read_timeout
  4. 保存后执行 sudo systemctl reload php-fpm
  5. 登进你天天看的监控后台(宝塔、Zabbix、云厂商控制台),给“PHP-FPM 当前活跃进程数”和“服务器内存使用率”加上报警规则,阈值设 85%

做完这五步,下次 502 来敲门,你至少能笑着回一句:“稍等,我刚加固过。”