nginx 实现 dns 的 udp 负载均衡需启用 stream 模块(≥1.9.13)、配置 udp 监听、upstream 分组及 dns 协议级 health_check,通过 proxy_responses 1 和 reuseport 实现低延迟透传。

用 Nginx 实现 DNS 的 UDP 负载均衡,核心是启用 stream 模块并正确配置 UDP 监听、后端分组与健康检查。它不解析 DNS 内容,只做四层透传,因此延迟低、吞吐高,特别适合权威 DNS 或递归 DNS 集群的前置代理。
确认基础支持与系统准备
Nginx 必须编译时启用 --with-stream(含 --with-stream_ssl_module 可选),且版本 ≥ 1.9.13(UDP 支持起始版);推荐使用 1.22+ 或 1.24+ 稳定版以获得完整 health_check 功能。运行 nginx -V 2>&1 | grep -o with-stream 验证模块存在。
还需调整系统级限制:DNS 查询并发高,需增大文件描述符上限(/etc/security/limits.conf 中设置 nginx soft nofile 65536 和 hard nofile 65536),并确保内核参数 net.core.somaxconn 和 net.ipv4.ip_local_port_range 适配高连接场景。
配置 stream 块实现 UDP 负载均衡
DNS 使用 UDP/53,Nginx 需显式声明 udp 协议,并启用 reuseport 提升多核处理效率。典型配置如下:
/usr/local/nginx/conf/tcp.d/dns.conf
stream {
upstream dns_servers {
server 192.168.65.131:53;
server 192.168.65.132:53;
least_conn; # 更适合 DNS 这类短连接但突发密集的场景
}
<pre class="brush:php;toolbar:false;">server {
listen 53 udp reuseport;
proxy_pass dns_servers;
proxy_timeout 30s; # 单次查询等待响应超时
proxy_responses 1; # UDP 无握手,收到首个包即认为成功
}}
注意:proxy_responses 1 是关键项——它告诉 Nginx 不等待完整会话,只要上游返回一个 UDP 包就关闭本次代理连接,避免阻塞。
添加 DNS 协议级健康检查(Nginx ≥ 1.19.0)
UDP 无连接,不能靠 TCP 连通性判断存活。需用 match 块模拟 DNS 查询探测:
- 定义匹配规则:期望收到 DNS 响应标志位
\x81\x80(标准响应码,表示 QR=1, RCODE=0) - 在 upstream 中启用
health_check,指定探测间隔与判定阈值
示例片段:
match dns_response {
expect ~* "\x81\x80";
}
<p>upstream dns_servers {
server 192.168.65.131:53;
server 192.168.65.132:53;
health_check interval=5s passes=2 fails=3 match=dns_response;
least_conn;
}</p>
这样 Nginx 每 5 秒向每个后端发一个空 UDP 包(或自定义 send),验证是否返回合规响应,自动剔除异常节点。
验证与常见问题排查
配置完成后,执行 nginx -t 检查语法,再 nginx -s reload 生效。验证方式包括:
- 用
dig @192.168.65.135 xiaott.org +short多次请求,观察返回 IP 是否在两台后端间轮换 - 抓包确认:在 Nginx 机器上
tcpdump -i any port 53 and udp,能看到入向请求被分发到不同后端 - 若请求无响应,先检查防火墙是否放行 UDP/53(
iptables -L -n -v | grep :53),再确认后端 BIND 是否监听0.0.0.0:53 udp(而非仅127.0.0.1) - 出现
no such file or directory错误,通常是路径引用错误(如 include 的 conf 文件不存在)或 SELinux 限制,可临时setenforce 0排查











