Nginx中动态upstream域名解析失效问题解决的几种方法

 更新时间:2026年04月19日 11:26:41   作者:舞夢輝影  
本文主要介绍了Nginx中实现动态解析upstream域名的方法,强调了使用resolver指令与变量触发、作用域正确、配置兼容三要素的重要性,并提供了四种解决方案,下面就来详细的介绍一下

要让 Nginx 对 upstream 中的域名做运行时动态解析(而非仅启动时静态解析),关键不是简单加个 resolver,而是必须满足“变量触发 + 作用域正确 + 配置兼容”三要素。直接写 proxy_pass http://api.example.com; 或在 upstream 块里写 server api.example.com;,无论有没有 resolver,都只会解析一次。、

问题根源

# ❌ 错误示例:仅在启动时解析一次
upstream backend {
    server api.example.com:8080;  # 启动时解析,之后永远不变
}
location / {
    proxy_pass http://backend;
}

当后端 IP 变化时,Nginx 仍指向旧 IP,导致请求失败。

解决方案一:使用 resolver 指令(推荐)

基础配置

http {
    # 1. 配置 DNS 解析器(必须放在 http/server/location 层级)
    resolver 8.8.8.8 8.8.4.4 valid=10s;  # Google DNS,TTL 10秒
    resolver_timeout 5s;
    server {
        listen 80;
        location /api/ {
            # 2. 使用变量强制动态解析
            set $backend "api.example.com";
            proxy_pass http://$backend:8080;
            # 3. 关键:配合 resolver 实现每次请求都解析(或按 TTL 缓存)
            proxy_http_version 1.1;
            proxy_set_header Host $host;
        }
    }
}

进阶:Consul/内部 DNS 服务发现

http {
    # 针对 Consul 或 Kubernetes CoreDNS 优化
    resolver 127.0.0.1:8600 valid=5s;  # Consul DNS 端口
    resolver_timeout 2s;
    # 可选:指定 DNS 搜索域
    resolver 10.96.0.10 valid=5s ipv6=off;  # K8s CoreDNS,禁用 IPv6 避免延迟
    server {
        location / {
            set $svc "user-service.service.consul";
            proxy_pass http://$svc:8080;
            # 连接池优化:避免频繁 DNS 查询影响性能
            proxy_connect_timeout 2s;
            proxy_send_timeout 5s;
            proxy_read_timeout 10s;
        }
    }
}

解决方案二:upstream + resolver 组合(高可用)

需要负载均衡时,结合 upstream 动态解析:

http {
    resolver 10.0.0.2 valid=10s;
    # 定义 upstream 但使用域名变量
    upstream dynamic_backend {
        server 0.0.0.0;  # 占位,实际在 location 中解析
        # 健康检查(需要 nginx_upstream_check_module 或商业版)
        check interval=3000 rise=2 fall=3 timeout=1000 type=http;
        check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx;
    }
    server {
        location / {
            # 关键:使用变量触发 resolver
            set $backend_nodes "app.service.consul";
            # 通过 Lua 或 split_clients 实现动态选择(见方案三)
            proxy_pass http://$backend_nodes;
        }
    }
}

解决方案三:Lua 动态解析(OpenResty)

最灵活的方式,完全控制解析逻辑:

http {
    resolver 127.0.0.1:8600;
    server {
        location / {
            access_by_lua_block {
                local resolver = require "resty.dns.resolver"
                -- 1. 创建 DNS 客户端
                local dns, err = resolver:new{
                    nameservers = {"127.0.0.1", {"127.0.0.1", 8600}},
                    retrans = 2,
                    timeout = 1000,
                }
                -- 2. 查询 SRV 记录(Consul 推荐)
                local answers, err = dns:query("user-service.service.consul", 
                                               {qtype = dns.TYPE_SRV})
                -- 3. 动态选择节点(加权随机)
                if answers then
                    local target = answers[math.random(1, #answers)]
                    ngx.var.target_host = target.target
                    ngx.var.target_port = target.port
                else
                    -- 降级到静态配置
                    ngx.var.target_host = "127.0.0.1"
                    ngx.var.target_port = "8080"
                end
            }
            set $target_host "";
            set $target_port "";
            proxy_pass http://$target_host:$target_port;
        }
    }
}

解决方案四:Nginx Plus(商业版)

如果预算允许,Nginx Plus 提供原生动态解析:

upstream backend {
    zone upstream_backend 64k;
    # 关键:resolve 参数启用动态 DNS
    server api.example.com:8080 resolve;
    # 健康检查
    health_check interval=5s fails=3 passes=2;
}
server {
    location / {
        proxy_pass http://backend;
        health_check;
    }
}

关键配置参数详解

参数说明推荐值
valid=10sDNS 缓存 TTL微服务环境 5-10s,稳定服务 60s
ipv6=off禁用 IPv6 解析纯 IPv4 环境建议关闭,避免延迟
resolver_timeout单次 DNS 查询超时2-5s
resolver 位置必须在 http{}、server{} 或 location{}通常放 http{} 全局

常见问题排查

1. 解析不生效(仍使用旧 IP)

# ❌ 错误:直接写死域名,不会触发 resolver
proxy_pass http://api.example.com:8080;
# ✅ 正确:使用变量强制动态解析
set $backend "api.example.com";
proxy_pass http://$backend:8080;

2. 日志中出现 no resolver defined

# 错误原因:location 中使用了变量,但上级未定义 resolver
# 解决:确保 resolver 在 http 或 server 层级定义
http {
    resolver 8.8.8.8;  # 必须在这里定义,不能只在 location
}

3. DNS 查询延迟高

# 优化:本地 DNS 缓存 + 连接池
resolver 127.0.0.1 valid=5s;  # 指向本地 dnsmasq/unbound
upstream backend {
    keepalive 100;  # 连接池,避免每次新建连接
    keepalive_timeout 60s;
    keepalive_requests 1000;
}

生产环境完整配置模板

http {
    # DNS 配置(多可用区冗余)
    resolver 10.0.0.2 10.0.0.3 valid=10s ipv6=off;
    resolver_timeout 3s;
    # 日志记录解析详情(调试用)
    log_format dns_log '$remote_addr - $upstream_addr [$time_local] '
                      '"$request" $status $body_bytes_sent '
                      'upstream: "$upstream_addr" '
                      'resolve: "$upstream_http_host"';
    upstream app_servers {
        zone app_zone 64k;
        keepalive 100;
        # 占位 server,实际在 location 中动态解析
        server 127.0.0.1:1 backup;  # 备用,防止启动失败
    }
    server {
        listen 80;
        access_log /var/log/nginx/access.log dns_log;
        location / {
            # 动态解析核心配置
            set $backend_host "app.service.consul";
            set $backend_port "8080";
            proxy_pass http://$backend_host:$backend_port;
            # 错误降级
            proxy_intercept_errors on;
            error_page 502 503 504 = @fallback;
            # 连接优化
            proxy_connect_timeout 3s;
            proxy_next_upstream error timeout http_502 http_503 http_504;
            proxy_next_upstream_tries 2;
        }
        location @fallback {
            internal;
            return 503 '{"error":"Service Unavailable","retry_after":10}';
        }
    }
}

核心要点:resolver + 变量 是实现动态 DNS 的黄金组合,务必确保使用 $variable 形式编写 proxy_pass,否则 Nginx 会优化为启动时静态解析。

到此这篇关于Nginx resolver指令解决动态upstream域名解析失效问题的文章就介绍到这了,更多相关Nginx upstream域名解析失效问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Nginx根据不同浏览器语言配置页面跳转的方法

    Nginx根据不同浏览器语言配置页面跳转的方法

    这篇文章主要介绍了Nginx根据不同浏览器语言配置页面跳转的方法,包括一个简体繁体的基本判断方法及实际根据中英文跳转的例子,需要的朋友可以参考下
    2016-04-04
  • 配置Nginx出现403(Forbidden)静态文件加载不出来的解决方法

    配置Nginx出现403(Forbidden)静态文件加载不出来的解决方法

    本文主要介绍了配置Nginx出现403(Forbidden)静态文件加载不出来的解决方法,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-12-12
  • Nginx 如何部署指定文件夹下的项目(本地测试)

    Nginx 如何部署指定文件夹下的项目(本地测试)

    这篇文章主要介绍了Nginx 如何部署指定文件夹下的项目(本地测试),分为配置vue.config.js,指定生成环境的包,配置路由模式为hash(history模式刷新后,找不到页面),本文讲解的非常详细,需要的朋友可以参考下
    2024-01-01
  • nginx反向代理时如何保持长连接

    nginx反向代理时如何保持长连接

    如果我们使用了nginx去作为反向代理或者负载均衡,从客户端过来的长连接请求就会被转换成短连接发送给服务器端。为了支持长连接,我们需要在nginx服务器上做一些配置。
    2020-10-10
  • Nginx四层负载均衡的配置指南

    Nginx四层负载均衡的配置指南

    当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃.为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力,这篇文章主要给大家介绍了关于Nginx四层负载均衡配置的相关资料,需要的朋友可以参考下
    2021-06-06
  • 解析Nginx中的日志模块及日志基本的初始化和过滤配置

    解析Nginx中的日志模块及日志基本的初始化和过滤配置

    ngx_errlog_module是Nginx中用来管理日志的模块,解析Nginx中的日志模块及日志基本的初始化和过滤配置,需要的朋友可以参考下
    2016-07-07
  • 解决nginx配置proxy_pass之后,响应变慢的问题

    解决nginx配置proxy_pass之后,响应变慢的问题

    这篇文章主要介绍了解决nginx配置proxy_pass之后,响应变慢的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Nginx本地配置SSL访问的实例教程

    Nginx本地配置SSL访问的实例教程

    当一个项目部署测试服后会遇到跨域、SSL证书、访问静态文件等各种问题,这个时候我们就可以采用Nginx来解决上述的问题,下面这篇文章主要给大家介绍了关于Nginx本地配置SSL访问的相关资料,需要的朋友可以参考下
    2022-05-05
  • windows下nginx+tomcat配置负载均衡的方法

    windows下nginx+tomcat配置负载均衡的方法

    这篇文章主要介绍了windows下nginx+tomcat配置负载均衡的方法,需要的朋友可以参考下
    2016-09-09
  • Nginx+Tomcat配置https的实现

    Nginx+Tomcat配置https的实现

    本文主要介绍了Nginx+Tomcat配置https的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04

最新评论