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配置同时支持http和https的两种方式

    Nginx配置同时支持http和https的两种方式

    现在的网站支持Https几乎是标配功能,Nginx能很好的支持Https功能,本文主要介绍了Nginx配置同时支持http和https的两种方式,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • centos6.4下nginx1.12.1安装教程

    centos6.4下nginx1.12.1安装教程

    这篇文章主要为大家详细介绍了centos6.4下nginx1.12.1安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • 国外著名论坛程序IPB(Invision Power Board)在nginx下的配置示例

    国外著名论坛程序IPB(Invision Power Board)在nginx下的配置示例

    这篇文章主要介绍了国外著名论坛程序IPB(Invision Power Board)在nginx下的配置示例,使用fastcgi配置模式,需要的朋友可以参考下
    2014-07-07
  • Nginx日志文件在哪及如何从中提取时间信息

    Nginx日志文件在哪及如何从中提取时间信息

    Nginx提供了一个非常灵活的日志记录功能,它可以使每个块的配置拥有各自独立的日志进行记录,并且根据记录内容的不同又分为访问日志和错误日志,这篇文章主要介绍了Nginx日志文件在哪及如何从中提取时间信息的相关资料,需要的朋友可以参考下
    2025-10-10
  • Nginx启动常见错误及解决方法

    Nginx启动常见错误及解决方法

    重新启动服务器发现报nginx: [error] open() "/usr/local/nginx/logs/nginx.pid" failed (2: No such file or directory)错误,怎么回事如何解决呢,下面脚本之家小编给大家解答下
    2016-08-08
  • nginx请求时找路径问题解决

    nginx请求时找路径问题解决

    当你安装了nginx的时候,为nginx配置了如下的location,想要去访问路径下面的内容,可是总是出现404,找不到文件,这是什么原因呢,今天我们就来解决这个问题,感兴趣的朋友一起看看吧
    2023-10-10
  • filebeat收集json格式的tomcat日志详解

    filebeat收集json格式的tomcat日志详解

    这篇文章主要为大家介绍了filebeat收集json格式的tomcat日志详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • nginx查看配置文件的操作方法

    nginx查看配置文件的操作方法

    nginx的配置放在nginx.conf文件中,一般我们可以使用以下命令查看服务器中存在的nginx.conf文件,这篇文章主要介绍了nginx查看配置文件,需要的朋友可以参考下
    2024-02-02
  • Nginx服务器上安装SSL证书方式

    Nginx服务器上安装SSL证书方式

    该文详细介绍了在Nginx服务器上搭建HTTPS的过程,包括检查和安装http_ssl_module模块、下载并配置SSL证书、修改nginx.conf文件及设置自动跳转HTTPS等步骤
    2026-04-04
  • 由于Nginx配置文件问题导致打不开网站unknown directive的解决

    由于Nginx配置文件问题导致打不开网站unknown directive的解决

    这篇文章主要介绍了由于Nginx配置文件问题导致打不开网站unknown directive,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06

最新评论