
发布时间:2026-10-03 00:55:52
腾讯云服务器 502 错误全链路排查:从安全组到后端超时
正文
后端一切正常,用户却反馈"网站打不开,报 502"。这类工单我每个月都要接好几单,最常见的误区是一看到 502 就去改 Nginx 配置,结果越改越乱。腾讯云服务器 502 错误本质上是网关或反向代理拿不到后端的有效响应,它只是链路中的一声报警,真正断掉的那一跳可能在安全组、在 Nginx、在 upstream 连接,也可能在后端进程本身。排查的正确姿势是沿链路分层定位,而不是凭感觉试参数。
这套方法我用了很多年,核心就一句话:先把"哪一层出的问题"用证据钉死,再动手。链路从上到下依次是公网、CLB 或轻量应用服务器防火墙、Nginx、upstream、后端进程,每一层都有自己的日志和命令,逐层排除,比拍脑袋改参数靠谱得多。
先把 502 和 504 分开:一个是连接没成,一个是等太久
这两个状态码经常被混着叫"服务器错误",但语义完全不同,方向错了会白白浪费时间。502 Bad Gateway 表示网关或代理从上游收到了无效响应,典型是后端进程没在监听、端口写错、连接被重置,或者后端刚崩掉。504 Gateway Timeout 表示网关成功连上了上游,但等响应等超时了,典型是后端处理太慢、数据库慢查询、下游接口卡住。
一句话记法:502 是"连不上或连得不干净",504 是"连上了但你不说话"。定位时先看是哪个角色抛出的状态码——是腾讯云负载均衡 CLB 抛的,还是本机 Nginx 抛的,还是 Nginx 到后端的这一跳。抛出的位置不同,日志入口和排查命令也不一样。先分清 502 和 504,再去谈参数,能省掉一大半无效操作。
顺着这个思路,还有几个码容易混。499 是客户端主动断开,多半是用户等不及把页面关了;503 更多指向后端过载或主动拒绝服务;而 502、504 都聚焦在网关与后端之间这一跳。Nginx 里常用 error_page 给 502 兜一个友好页面,结果用户看到的是一片正常样式,反而掩盖了真实状态,所以排障时别只看用户那一屏,去 access.log 里翻真实的上游状态码和上游响应时间。
定位断在哪一跳:链路分层与日志入口
从用户到后端,链路大致是:客户端 → 公网 → CLB 或轻量应用服务器防火墙 → Nginx → upstream 后端。逐层看证据,别跳步。
第一层看网络可达性,安全组和轻量防火墙有没有放行入站端口。如果这一层就断,用户看到的是连接超时而不是 502,所以能收到 502 说明流量至少到了网关。第二层看网关日志:Nginx 的 error.log 会明确写出是连接上游被拒绝(connection refused)、上游读取超时(upstream timed out),还是上游提前关闭连接。第三层看本机监听:ss -lntp 确认后端进程是否真的在 127.0.0.1 或 0.0.0.0 的目标端口上监听,curl -v http://127.0.0.1:端口 从本机直接打后端,能立刻区分"Nginx 的问题"还是"后端的问题"。
我习惯的定位顺序是:先 curl 本机后端,本机通就说明后端活着,问题在 Nginx 到后端之间;本机不通就先修后端。这个动作五分钟能做完,却能避免大量瞎猜。
再往细里走,可以用 curl -o /dev/null -s -w 'time_total:%{time_total}' 打本机后端看耗时,用 tcpdump 抓 127.0.0.1:端口,确认有没有 SYN 发出、有没有被回 RST,必要时用 mtr 看内网质量。CVM 的内网通信走私有网络 VPC,如果 Nginx 和后端分属不同可用区,跨 AZ 的延迟和抖动会被放大,而这一点在排障时经常被忽略。把"哪一层出的问题"用证据钉死,后面调参才有意义。
看日志也有小技巧:Nginx 的 error.log 通常带着 upstream 地址和错误原因,能直接区分后端是"拒绝连接"还是"读取超时";再对照 access.log 里的上游状态和响应时间,两条日志一交叉,基本就能锁定是哪一层。养成同时看 access.log 和 error.log 的习惯,比只盯其中一个查得快得多。如果后端是多实例,还要确认是不是只有部分实例异常、健康检查有没有把坏实例及时摘掉,否则 502 会一直零星地冒出来。
upstream 超时参数:proxy_connect、read、send 三者怎么分工
确认是超时类问题后,就要看 Nginx 的 proxy 超时三兄弟。proxy_connect_timeout 管的是"和后端建立连接"的超时,设太小会在后端繁忙、backlog 排队时误报 502;proxy_read_timeout 管的是"连接建立后,两次读操作之间的等待时间",它才是 504 的主要嫌疑;proxy_send_timeout 管的是"向后端发送请求"的超时。三者默认多在几十秒量级,代理长耗时任务时不调整就会频繁 504。
调整的思路是:先确认后端正常处理需要多久(看应用日志里的耗时),再把 proxy_read_timeout 设到略大于正常耗时的值,而不是无脑往大了加——设得太大,用户要干等很久才拿到错误,体验更差。同时别忘了 keepalive 和 proxy_http_version 1.1,上游长连接配好能明显减少连接建立开销。如果用的是 CLB,反向代理层的超时是另一套参数,Nginx 改好之后还要确认 CLB 的会话保持和超时设置,两层要对齐。超时参数不是越大越好,而是要略大于后端真实处理耗时的上限。
还有个容易被忽视的 proxy_next_upstream:默认某些错误会触发 Nginx 自动重试下一个上游,上游只配了一台、又没做幂等时,重试反而会放大问题,得按业务确认哪些错误允许重试。当 upstream 里写的是域名而不是固定 IP,还要注意 resolver 和变量代理的写法,否则 DNS 记录变了、Nginx 还抱着旧地址不放,表现就是一会儿好一会儿 502。把这些和超时参数放在一起看,才算把 upstream 这一层配完整。
连接数与本机端口耗尽:高峰期才冒出来的 502
有一类 502 特别阴,平时好好的,一到高峰期就集中出现,重启又能缓解一阵。这种情况常常和连接数、本机端口耗尽有关。Nginx 作为反向代理,每次连后端都要占用一个临时端口,net.ipv4.ip_local_port_range 决定了可用范围,而大量 TIME_WAIT 状态的连接会迅速把这个范围吃掉,导致新连接无端口可用,直接报 502。
观察手段:ss -s 看各状态连接计数,ss -tan state time-wait | wc -l 数 TIME_WAIT 数量。缓解手段是组合拳:开启 net.ipv4.tcp_tw_reuse,让 TIME_WAIT 的连接可以被复用于出站连接;调大 ip_local_port_range 扩大端口池;让 Nginx 到后端使用 keepalive 长连接,从源头减少连接建立次数。同时别忽略 worker_connections 和 worker_rlimit_nofile,文件描述符或连接上限打满,也会表现成间歇性 502。负载均衡或前端连接数上来了,本机这些参数跟不上,就会成为瓶颈。
内核侧的接收队列同样关键:net.core.somaxconn 和 net.ipv4.tcp_max_syn_backlog 设得太小,新连接会在队列里被直接丢掉,客户端侧看到的就是连接失败。Nginx 的 listen 里 backlog= 的取值也要和内核参数对齐,两边不一致时以较小者为准。高峰期的 502 往往不是某一个参数的问题,而是端口、文件描述符、连接队列、keepalive 这组参数没配齐,需要成套调整,改一个往往按不下葫芦。
后端被 OOM 杀掉:从内核日志找线索
如果 502 是间歇性的、伴随机器变卡或应用莫名重启,就要怀疑后端进程被系统的 OOM Killer 干掉了。Linux 内存吃紧时,内核会按 oom_score 挑一个进程杀掉,后端进程往往是最"肥"的那个,于是表现为后端突然消失、Nginx 立刻报 502,过一会儿进程被守护脚本拉起又恢复正常。
线索在几处:dmesg -T 或 journalctl -k 里搜 "Out of memory" 和 "Killed process",能看到被杀进程名和 PID;容器的 docker inspect 里如果 OOMKilled 为 true,说明是被容器内存上限杀的;系统层面再配合 free -h、vmstat 看内存与 swap 情况。处置上,先确认是真实内存不足还是内存泄漏,短期可以给进程加内存或调大容器限制,长期要看应用本身。凡是"时好时坏"的 502,都应该先排查一次 OOM,把这条线排除掉。
要更主动一点,可以给关键进程调低 oom_score_adj,让它不那么容易被优先杀掉;容器场景则要确认 cgroup 的内存上限设得是否合理,限制给小了,负载一上来就会被自己人干掉。判断到底是内存泄漏还是瞬时峰值,可以在一段时间里周期性记录进程的常驻内存,看它是持续爬升还是围绕峰值波动,这直接决定了你该扩容内存,还是该回去改代码。另外,swap 的配置也会干扰判断:开了 swap 的机器,内存在真正耗尽之前会先大量换页,表现是系统变卡、响应变慢而不是直接杀进程,这种情况要结合 swap 使用率一起看,别以为进程没被杀就万事大吉。
常见状态码与成因的对应关系,可以先照着这张表缩小范围:
状态码来源 表现 最可能成因 先查什么 处置方向
Nginx 502 瞬间报错后端日志无记录 后端未监听或端口写错 ss 看监听与 curl 本机 修正端口与监听地址
Nginx 502 偶发连接被重置 后端进程崩溃或被重启 error.log 与进程守护 修后端稳定性
Nginx 504 等待很久后超时 后端处理慢或慢查询 proxy_read_timeout 调超时并优化后端
网关 502 请求根本到不了后端 安全组或防火墙未放行 控制台安全组规则 放行后端端口
高峰 502 集中出现在峰值时段 端口耗尽 backlog 溢出 ss 统计连接状态 调内核与开长连接
间歇 502 进程莫名消失 被 OOM Killer 杀掉 内核日志与容器状态 扩容内存或修泄漏
FAQ
Q:502 和 504 到底怎么快速区分?
A:502 是网关连不上后端或收到无效响应,方向偏"连接失败";504 是网关连上了后端但等响应超时,方向偏"后端太慢"。看 Nginx error.log 里是 connection refused 还是 upstream timed out,基本就能定性。
Q:改了 Nginx 配置还是 502,为什么?
A:先 curl 本机后端端口,确认后端本身是否正常。如果本机都不通,问题在后端进程或端口,改 Nginx 没用;如果本机通、经 Nginx 不通,再看 upstream 配置、安全组和 CLB 这一跳。
Q:高峰期偶发 502,怎么判断是不是端口耗尽?
A:用 ss -s 看整体连接状态,用 ss -tan state time-wait | wc -l 数 TIME_WAIT。数量长期很高、且伴随 ip_local_port_range 用尽,就开 tcp_tw_reuse、扩大端口池,并让 Nginx 到后端走 keepalive。
Q:怎么确认后端是不是被 OOM 杀了?
A:在 dmesg -T 或 journalctl -k 里搜 "Out of memory" 和 "Killed process";容器场景看 docker inspect 的 OOMKilled 字段。发现被杀后,短期扩容内存或调大限制,长期排查内存泄漏