DNS 域名解析问题排查指南:多 IP 绑定、负载均衡故障与 Nginx 配置实战

AI辅助声明:本文内容经过AI辅助整理和优化,结合2026年最新DNS故障排查实践进行更新。

更新说明:补充了最新的DNS故障排查工具和方法。

引言

在运维生产环境时,域名解析问题是最常见的故障类型之一。当用户反馈”网站时好时坏”或”部分地区无法访问”时,往往与 DNS 配置有关。本文以真实的排查案例为基础,详细介绍 DNS 多 IP 绑定场景下的问题定位方法和解决方案。

问题场景描述

故障现象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌─────────────────────────────────────────────────────────────────────┐
│ 故障现象:域名访问时好时坏 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 用户反馈: │
│ ├── 通过域名访问网站,有时正常,有时失败 │
│ ├── 浏览器显示 "无法连接到服务器" 或 "连接超时" │
│ └── 直接访问 IP 地址没有问题 │
│ │
│ 初步判断: │
│ ┌──────────────┐ DNS 轮询 ┌──────────────┐ │
│ │ 用户浏览器 │ ─────────────► │ DNS 服务器 │ │
│ └──────────────┘ └───────┬──────┘ │
│ │ │
│ 返回多个 A 记录 │ │
│ ▼ │
│ ┌───────────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│
│ │ 服务器 A │ │ 服务器 B │ │ 服务器 C ││
│ │ 192.0.2.1│ │192.0.2.2 │ │192.0.2.3 ││
│ └────┬─────┘ └────┬─────┘ └────┬─────┘│
│ │ │ │ │
│ └─────────────────────┴─────────────────────┘ │
│ │ │
│ 其中服务器 B 已下线或故障 │
│ │ │
│ 用户访问失败 │
│ │
└─────────────────────────────────────────────────────────────────────┘

DNS 基础概念

DNS 记录类型

记录类型 说明 示例
A 将域名指向 IPv4 地址 example.com. A 192.0.2.1
AAAA 将域名指向 IPv6 地址 example.com. AAAA 2001:db8::1
CNAME 域名别名 www.example.com. CNAME example.com.
MX 邮件交换记录 example.com. MX 10 mail.example.com.
TXT 文本记录 用于验证、SPF 等
NS 域名服务器记录 指定 DNS 服务器

多 A 记录负载均衡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌─────────────────────────────────────────────────────────────────────┐
│ DNS 轮询负载均衡原理 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ DNS 配置: │
│ │
│ example.com. 300 IN A 192.0.2.1 (服务器 1) │
│ example.com. 300 IN A 192.0.2.2 (服务器 2) │
│ example.com. 300 IN A 192.0.2.3 (服务器 3) │
│ │
│ 轮询策略: │
│ │
│ 第一次查询 ──► 返回 [192.0.2.1, 192.0.2.2, 192.0.2.3] │
│ 第二次查询 ──► 返回 [192.0.2.2, 192.0.2.3, 192.0.2.1] │
│ 第三次查询 ──► 返回 [192.0.2.3, 192.0.2.1, 192.0.2.2] │
│ │
│ 客户端行为: │
│ ├── 大多数客户端会尝试第一个 IP │
│ ├── 失败后尝试第二个 IP │
│ └── 所有 IP 失败后报告错误 │
│ │
│ 问题场景: │
│ └── 如果其中某个 IP 对应的服务器故障,部分用户会访问失败 │
│ │
└─────────────────────────────────────────────────────────────────────┘

问题排查流程

第一步:确认 DNS 解析结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用 dig 查询 DNS 记录
dig example.com A

# 指定 DNS 服务器查询
dig @8.8.8.8 example.com A
dig @1.1.1.1 example.com A

# 查看完整的解析过程
dig +trace example.com

# 使用 nslookup
nslookup example.com
nslookup example.com 8.8.8.8

# 使用 host 命令
host example.com
host -a example.com

第二步:验证各 IP 的连通性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 批量 ping 测试
for ip in 192.0.2.1 192.0.2.2 192.0.2.3; do
echo "Testing $ip..."
ping -c 3 $ip
done

# 使用 fping 并行测试
fping -c 3 192.0.2.1 192.0.2.2 192.0.2.3

# HTTP 请求测试
for ip in 192.0.2.1 192.0.2.2 192.0.2.3; do
echo "Testing HTTP on $ip..."
curl -I -H "Host: example.com" http://$ip/ --connect-timeout 5
done

第三步:Nginx 配置检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 配置 Nginx 监听所有需要的 IP
server {
listen 80;
listen 192.0.2.1:80;
listen 192.0.2.2:80;
listen 192.0.2.3:80; # 确保这个 IP 也在 Nginx 配置中

server_name example.com www.example.com;

location / {
root /var/www/html;
index index.html;
}
}

# 或者使用默认 server_name 匹配所有
server {
listen 80 default_server;
server_name _;

location / {
root /var/www/html;
index index.html;
}
}

完整排查案例

案例背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─────────────────────────────────────────────────────────────────────┐
│ 案例:渠道接入时的域名问题 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 场景: │
│ - 游戏接入新渠道,渠道方提供域名指向我方服务器 │
│ - 渠道方域名配置:game.channel.com ──► 我方 IP 列表 │
│ - 用户通过渠道下载游戏,游戏内使用渠道域名连接服务器 │
│ │
│ 故障现象: │
│ - 部分用户反馈游戏登录失败 │
│ - 有时可以登录,有时失败 │
│ - 问题随机出现,难以复现 │
│ │
└─────────────────────────────────────────────────────────────────────┘

排查步骤详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 1. 获取渠道方域名解析的 IP 列表
dig game.channel.com A +short

# 输出示例:
# 203.0.113.10
# 203.0.113.11
# 203.0.113.12

# 2. 逐一测试每个 IP 的连通性
echo "=== 测试 IP 连通性 ==="
for ip in 203.0.113.10 203.0.113.11 203.0.113.12; do
echo -n "Testing $ip: "
if ping -c 1 -W 2 $ip > /dev/null 2>&1; then
echo "OK"
else
echo "FAILED"
fi
done

# 3. 测试每个 IP 的 HTTP 服务
echo "=== 测试 HTTP 服务 ==="
for ip in 203.0.113.10 203.0.113.11 203.0.113.12; do
echo -n "Testing HTTP on $ip: "
response=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Host: game.channel.com" \
--connect-timeout 5 \
http://$ip/health 2>/dev/null)
echo "HTTP $response"
done

# 4. 检查本地服务器是否监听这些 IP
echo "=== 检查本地监听端口 ==="
ss -tlnp | grep :80
netstat -tlnp | grep :80

# 5. 查看 Nginx 配置
echo "=== Nginx 配置检查 ==="
grep -r "listen" /etc/nginx/conf.d/
nginx -t # 测试配置是否正确

发现问题

1
2
3
4
5
6
7
8
9
# 排查结果:
# - 203.0.113.10: OK, HTTP 200
# - 203.0.113.11: FAILED, 无法 ping 通
# - 203.0.113.12: OK, HTTP 200

# 检查 Nginx 配置发现:
# - 服务器只监听了 203.0.113.10 和 203.0.113.12
# - 203.0.113.11 没有配置在 Nginx 中
# - 或者 203.0.113.11 对应的服务器已经下线

解决方案

方案一:通知渠道方修改 DNS(推荐)

1
2
3
4
5
6
7
# 联系渠道方,要求移除失效的 IP
# 正确的 DNS 配置应该是:
#
# game.channel.com. 300 IN A 203.0.113.10
# game.channel.com. 300 IN A 203.0.113.12
#
# 移除:203.0.113.11

方案二:在 Nginx 中配置所有 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# /etc/nginx/conf.d/game.conf

upstream game_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}

server {
# 监听渠道方绑定的所有 IP
listen 203.0.113.10:80;
listen 203.0.113.11:80; # 即使这个 IP 不在本机也要配置
listen 203.0.113.12:80;

server_name game.channel.com;

location / {
proxy_pass http://game_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

# 如果某些 IP 不在本机,使用防火墙重定向或负载均衡器

方案三:使用负载均衡器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌─────────────────────────────────────────────────────────────────────┐
│ 使用负载均衡器统一入口 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 架构改造: │
│ │
│ DNS 记录 │
│ game.channel.com ─────────────────────► 负载均衡器 IP │
│ │ │
│ ┌───────────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐│
│ │ 服务器 1 │ │ 服务器 2 │ │ 服务器 3 ││
│ │192.168.1.│ │192.168.1.│ │192.168.1.││
│ └──────────┘ └──────────┘ └──────────┘│
│ │
│ 优势: │
│ ├── 统一入口,DNS 只配置一个 IP │
│ ├── 负载均衡器自动检测后端健康状态 │
│ └── 故障服务器自动摘除,用户无感知 │
│ │
│ 常用负载均衡器: │
│ ├── Nginx / OpenResty │
│ ├── HAProxy │
│ ├── LVS (Linux Virtual Server) │
│ └── 云厂商 SLB (阿里云、AWS ELB 等) │
│ │
└─────────────────────────────────────────────────────────────────────┘

DNS 健康检查机制

HTTP 健康检查脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/bash
# dns_health_check.sh - DNS 多 IP 健康检查

DOMAIN="game.channel.com"
TIMEOUT=5
ALERT_WEBHOOK="https://hooks.slack.com/services/xxx"

# 获取所有 IP
IPS=$(dig +short $DOMAIN A)

echo "=== DNS Health Check for $DOMAIN ==="
echo "Time: $(date)"
echo ""

failed_ips=()

for ip in $IPS; do
echo -n "Checking $ip... "

# HTTP 检查
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
--connect-timeout $TIMEOUT \
-H "Host: $DOMAIN" \
http://$ip/health 2>/dev/null)

if [ "$http_code" = "200" ]; then
echo "OK (HTTP 200)"
else
echo "FAILED (HTTP ${http_code:-timeout})"
failed_ips+=($ip)
fi
done

# 发送告警
if [ ${#failed_ips[@]} -gt 0 ]; then
message=" DNS Health Check Alert\nDomain: $DOMAIN\nFailed IPs: ${failed_ips[*]}\nTime: $(date)"

curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$message\"}" \
$ALERT_WEBHOOK
fi

自动故障转移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# dns_failover.py - 自动 DNS 故障转移

import dns.resolver
import requests
import json

class DNSFailover:
def __init__(self, domain, health_endpoint="/health"):
self.domain = domain
self.health_endpoint = health_endpoint
self.healthy_ips = []

def get_dns_ips(self):
"""获取 DNS 解析的所有 IP"""
try:
answers = dns.resolver.resolve(self.domain, 'A')
return [str(rdata) for rdata in answers]
except Exception as e:
print(f"DNS query failed: {e}")
return []

def check_ip_health(self, ip):
"""检查单个 IP 的健康状态"""
try:
response = requests.get(
f"http://{ip}{self.health_endpoint}",
headers={"Host": self.domain},
timeout=5
)
return response.status_code == 200
except:
return False

def update_healthy_ips(self):
"""更新健康 IP 列表"""
all_ips = self.get_dns_ips()
self.healthy_ips = [ip for ip in all_ips if self.check_ip_health(ip)]

# 保存到配置文件供应用使用
with open('/etc/app/healthy_ips.json', 'w') as f:
json.dump({
'domain': self.domain,
'healthy_ips': self.healthy_ips,
'all_ips': all_ips
}, f)

return self.healthy_ips

# 定时执行
if __name__ == '__main__':
import schedule
import time

failover = DNSFailover('game.channel.com')

# 每 30 秒检查一次
schedule.every(30).seconds.do(failover.update_healthy_ips)

while True:
schedule.run_pending()
time.sleep(1)

预防措施与最佳实践

DNS 配置检查清单

检查项 说明 工具
A 记录数量 确认绑定的 IP 都是有效的 dig +short
IP 连通性 所有 IP 都能 ping 通 ping / fping
服务可用性 所有 IP 的 HTTP/HTTPS 服务正常 curl
SSL 证书 所有 IP 的证书配置正确 openssl s_client
TTL 设置 合理的 TTL 值便于故障转移 dig

推荐的 DNS 架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
┌─────────────────────────────────────────────────────────────────────┐
│ 高可用 DNS 架构推荐 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 方案一:负载均衡器模式(推荐) │
│ │
│ DNS: example.com ──► 负载均衡器 VIP │
│ │ │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ [Server 1] [Server 2] [Server 3] │
│ (Health Check 自动摘除故障节点) │
│ │
│ 优点: │
│ - 用户只需要配置一个 IP │
│ - 故障自动切换,对用户透明 │
│ - 支持加权负载均衡 │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 方案二:Anycast 模式(大型应用) │
│ │
│ DNS: example.com ──► Anycast IP │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [POP 1] [POP 2] [POP 3] │
│ (北京) (上海) (广州) │
│ │ │ │ │
│ └─────────────┴─────────────┘ │
│ 后端服务器集群 │
│ │
│ 优点: │
│ - 用户访问最近的节点 │
│ - 单点故障自动切换 │
│ - 全球加速 │
│ │
└─────────────────────────────────────────────────────────────────────┘

TTL 设置建议

场景 建议 TTL 说明
稳定环境 3600s (1小时) 减少 DNS 查询压力
故障转移 60s (1分钟) 快速切换,但增加查询量
灰度发布 300s (5分钟) 平衡灵活性和性能
DDoS 应急 10s 快速切换到高防 IP

总结

DNS 域名解析问题的排查要点:

  1. 问题定位dig / nslookup 查询 DNS 记录,确认所有绑定的 IP
  2. 连通性测试:使用 pingcurl 逐一测试每个 IP 的连通性和服务可用性
  3. 配置检查:确认 Nginx/服务器监听所有需要的 IP 地址
  4. 根本解决
    • 通知域名管理员移除失效 IP
    • 或配置服务器监听所有绑定 IP
  5. 预防措施
    • 使用负载均衡器统一入口
    • 建立 DNS 健康检查机制
    • 合理设置 TTL 值便于故障切换
  6. 监控告警:建立自动化监控,及时发现 DNS 配置异常

通过系统化的排查流程和合理的架构设计,可以有效避免和解决 DNS 多 IP 绑定带来的访问不稳定问题。