正在加载ing...

文章背景图

一次 504 Gateway Timeout 的排障记:Nginx DNS 缓存引发的血案

2026-06-14
0
-
- 分钟

背景

今天,我的一个网站突然无法访问,浏览器显示 504 Gateway Time-out,响应头里的 Server 是 openresty

这类问题通常是反向代理在连接上游时超时。下面把这次完整的排查与修复过程记录下来,便于以后遇到类似问题时快速复盘。


整体架构

  • 用户请求先到域名 A

  • 域名 A 解析到一台 OpenResty 反向代理机器(下文称"代理机")

  • OpenResty 再把请求转发给 http://域名B:端口,实际就是上游服务所在的机器(下文称"上游机")

这次故障发生在 OpenResty 到上游这一段。

由于服务器用的是自己申请的家宽公网ip,所以运营商不开放80和443端口,而且ip是动态的,会变化


排查过程

1) 先确认上游服务是否正常

在上游机直接访问本地服务端口:

curl -s http://localhost:端口/

能看到页面内容,说明上游服务本身没有挂。

2) 再看 OpenResty 的配置

登录代理机后,通过容器方式查看配置:

docker exec 容器名 nginx -T

可以看到关键代理配置:

location ^~ / {
    proxy_pass http://域名B:端口;
    # ...
}

3) 关键一步:看 error.log

这次排障最关键的信息来自 OpenResty 的错误日志:

# 在容器内
tail -50 /www/sites/域名A/log/error.log

日志里出现了类似这样的报错:

upstream timed out (110: Connection timed out) while connecting to upstream,
client: xx.xx.xx.xx, server: 域名A,
request: "GET /path HTTP/1.1",
upstream: "http://旧IP:端口/path"

这里有两个关键点:

  1. OpenResty 把请求代理到了一个旧 IP

  2. 这个旧 IP 连不上

4) 做对比验证

在同一台机器里用 getent hostsdig 查询域名 B:

getent hosts 域名B
# 新IP  域名B

也就是说,域名 B 当前解析出来的 IP 应该是新IP

但错误日志里 OpenResty 却去连了旧IP

这就说明:不是上游挂了,而是 OpenResty 在拿一个旧的解析结果去连。


根因:Nginx 的 DNS 缓存机制

问题的根因就是 proxy_pass 里写了域名,而且没有额外配置 DNS 解析策略。

在默认情况下,像这样的写法:

proxy_pass http://域名B:端口;

Nginx/OpenResty 会在启动或 reload 配置时把域名解析成 IP,之后长期使用这个结果。

所以当域名背后的 IP 发生了变化,但 OpenResty 一直拿着旧地址去做连接,自然就会出现 504。


修复方式

方案一:临时重启 OpenResty

docker restart 容器名

重启后,Nginx 会重新解析域名,问题通常会立即恢复。

方案二:让 Nginx 每次请求都重新解析 DNS(推荐)

要从根本上解决,需要在代理配置里改成动态解析的方式:

# 原来的写法
proxy_pass http://域名B:端口;
​
# 修改后的写法
resolver 1.1.1.1 valid=30s;
set $upstream 域名B:端口;
proxy_pass http://$upstream;

为什么要这样改:

  • resolver 1.1.1.1 valid=30s;:指定 Nginx 使用 1.1.1.1 做 DNS 查询,并且缓存 30 秒

  • set $upstream 域名B:35000;:把目标地址放进变量里

  • proxy_pass http://$upstream;:当 proxy_pass 使用变量时,Nginx 会在运行时重新解析域名

这样即使域名背后的 IP 再变化,OpenResty 也能较快地切换到新的地址,而不会一直抱着旧 IP 不放。


本次定位问题的关键信息

这次能快速定位,主要是靠两点:

  1. error.log 里的 upstream IP 它直接暴露了 OpenResty 实际连的是哪一个 IP,而不是只告诉你"超时了"。

  2. 比对实际 DNS 解析结果 错误日志里连的是旧 IP,但当前 DNS 解析结果是一个新的 IP,这两者不一致,就能判断是 DNS 缓存问题。


这类问题的一般排障顺序

  1. 先确认上游服务是否真的在跑

  2. 看 Nginx/OpenResty 的 error.log,确认它实际连接的地址和端口

  3. 对比当前域名解析结果,确认是否是旧 IP

  4. 如果上游是容器,检查容器端口是否正常

  5. 如果是 DNS 缓存,考虑改成运行时动态解析


说明

这次不是 OpenResty 本身有 Bug,也不是上游服务直接宕机,而是 Nginx 在 proxy_pass 写域名时的默认缓存行为 引发了故障。

这类问题在生产环境里其实挺常见,尤其是域名背后 IP 发生迁移、切换服务器、或者上游地址调整时。


结论

这次 504 的本质是:

OpenResty 把请求代理到一个旧的上游 IP,导致连接超时。

解决方式也很明确:

临时可以重启 OpenResty;长期建议通过 resolver + set $upstream 的方式启用运行时 DNS 解析。

这样就能避免因为域名背后 IP 变化,再次出现类似 504。

原创

一次 504 Gateway Timeout 的排障记:Nginx DNS 缓存引发的血案

本文链接: 一次 504 Gateway Timeout 的排障记:Nginx DNS 缓存引发的血案

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

评论交流

文章目录