DNS
→ 返回 计算机网络
DNS(Domain Name System)是互联网的”地址簿”,将人类可读的域名解析为 IP 地址,同时承载邮件路由、服务发现、安全验证等功能。
DNS 层级结构
.(根域,Root)
├── com(顶级域 TLD)
│ ├── example.com(二级域 SLD,注册域)
│ │ ├── www.example.com(子域)
│ │ └── mail.example.com
│ └── google.com
├── org
├── cn(国家代码 TLD)
│ └── baidu.com.cn
└── (约 1500+ 个 TLD)
域名实际上是倒着读的:www.example.com 完整写法是 www.example.com.(末尾有根点)
DNS 服务器角色
| 角色 | 说明 |
|---|---|
| 根域名服务器 | 13 组(A~M),全球 1000+ 节点(Anycast),知道所有 TLD 服务器地址 |
| TLD 服务器 | 管理 .com/.cn 等,知道该 TLD 下所有注册域的权威 NS |
| 权威 DNS 服务器 | 存储域名的实际记录(A/CNAME/MX 等),由域名所有者管理 |
| 递归解析器(Resolver) | 代替客户端完成完整查询,有缓存(ISP 提供或 8.8.8.8/1.1.1.1) |
DNS 完整解析流程
浏览器输入 www.example.com:
① 浏览器缓存(有效期约 1 分钟)
② 操作系统缓存 + /etc/hosts 文件
③ 本地递归解析器(路由器/ISP/8.8.8.8)有缓存直接返回
④ 递归解析器向根服务器迭代查询:
Resolver ──► 根服务器:".com 的 NS 在哪?"
根服务器 ──► "去问 a.gtld-servers.net"
⑤ Resolver ──► .com TLD 服务器:"example.com 的 NS 在哪?"
TLD 服务器 ──► "去问 ns1.example.com"(权威 NS)
⑥ Resolver ──► ns1.example.com:"www.example.com 的 A 记录?"
权威 ──► "93.184.216.34,TTL=3600"
⑦ Resolver 缓存并返回给客户端
客户端建立 TCP 连接到 93.184.216.34
递归 vs 迭代
| 模式 | 发起方 | 说明 |
|---|---|---|
| 递归查询 | 客户端 → Resolver | 客户端问 Resolver,Resolver 帮你一路查到底并返回最终结果 |
| 迭代查询 | Resolver → 各权威服务器 | Resolver 每次只得到”去问谁”的指引,自己逐步查询 |
DNS 记录类型
常用记录
| 类型 | 说明 | 示例 |
|---|---|---|
| A | 域名 → IPv4 | example.com. 3600 IN A 93.184.216.34 |
| AAAA | 域名 → IPv6 | example.com. 3600 IN AAAA 2001:db8::1 |
| CNAME | 别名 → 另一个域名 | www CNAME example.com. |
| MX | 邮件服务器(含优先级) | example.com. MX 10 mail.example.com. |
| TXT | 任意文本 | SPF、DKIM、域名验证、Google Site Verify |
| NS | 权威 DNS 服务器 | example.com. NS ns1.example.com. |
| PTR | IP → 域名(反向解析) | 34.216.184.93.in-addr.arpa. PTR example.com. |
进阶记录
| 类型 | 说明 |
|---|---|
| SOA | 区域权威信息(序号、刷新间隔、重试、过期、否定缓存 TTL) |
| SRV | 服务发现,指定主机 + 端口 + 优先级(Kubernetes、SIP、XMPP 使用) |
| CAA | 授权哪些 CA 可以颁发此域名的证书(防止错误签发) |
| HTTPS / SVCB | HTTPS 连接参数(端口、ECH 密钥、ALPN),HTTP/3 发现依赖此记录 |
| DNSKEY | DNSSEC 公钥 |
| DS | 子区域 DNSKEY 的摘要,用于建立信任链 |
| RRSIG | 资源记录的数字签名(DNSSEC) |
区域文件格式(Zone File)
; example.com 区域文件
$ORIGIN example.com.
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2024010101 ; 序号(Serial)
3600 ; 刷新(Refresh)
900 ; 重试(Retry)
604800 ; 过期(Expire)
300 ) ; 否定缓存 TTL(Negative TTL)
; NS 记录
IN NS ns1.example.com.
IN NS ns2.example.com.
; A 记录
@ IN A 93.184.216.34
www IN A 93.184.216.34
api IN A 10.0.0.100
; CNAME
blog IN CNAME www.example.com.
; MX 记录(优先级 10 < 20,越小越优先)
@ IN MX 10 mail1.example.com.
@ IN MX 20 mail2.example.com.
; SRV(_service._proto.domain 优先级 权重 端口 目标)
_https._tcp IN SRV 0 5 443 www.example.com.
; TXT(SPF 邮件防伪造)
@ IN TXT "v=spf1 mx ~all"
; CAA(只允许 Let's Encrypt 签发证书)
@ IN CAA 0 issue "letsencrypt.org"TTL 与缓存策略
- TTL 大(3600~86400s):缓存时间长,减少查询,改动传播慢(等待旧缓存过期)
- TTL 小(60~300s):改动快速生效,但查询频率高,权威服务器压力大
域名迁移 TTL 策略
迁移前 2 天:将 TTL 从 86400 → 300(让旧缓存快速过期)
迁移当天: 修改 A 记录指向新 IP
迁移后 2 天:将 TTL 改回 86400
否定缓存(Negative Caching)
NXDOMAIN(域名不存在)响应也会被缓存,缓存时间由 SOA 的最小 TTL 决定,防止对不存在域名的重复查询。
DNS 负载均衡
轮询 DNS(Round-Robin DNS)
同一域名配置多条 A 记录,解析器每次轮流返回不同 IP:
www IN A 1.2.3.4
www IN A 1.2.3.5
www IN A 1.2.3.6缺点:无法感知后端健康状态,客户端缓存导致分配不均。
GeoDNS / 智能 DNS
根据查询者的地理位置返回不同 IP(CDN 和国内外分流的基础):
中国用户 DNS 查询 example.com → 返回 114.x.x.x(国内 CDN 节点)
美国用户 DNS 查询 example.com → 返回 1.2.x.x(美国 CDN 节点)
Anycast DNS
8.8.8.8、1.1.1.1 等公共 DNS 使用 Anycast:同一 IP 部署在全球多个节点,BGP 路由自动将请求导向最近节点,实现就近响应 + 高可用。
DNSSEC(DNS 安全扩展)
为 DNS 记录添加数字签名,防止缓存污染和中间人篡改:
信任链
根区域(.)
└── KSK 签名 ZSK → DNSKEY 记录
└── ZSK 签名所有 RR → RRSIG 记录
│
DS 记录(父区域存储子区域 DNSKEY 的哈希摘要)
│
.com TLD
└── DS → example.com DNSKEY
└── example.com A/MX/... 的 RRSIG
验证流程:递归解析器从根区域的信任锚(Trust Anchor)出发,逐级验证 DS → DNSKEY → RRSIG,确保整条链上每个签名都有效。
# 验证域名是否启用 DNSSEC
dig example.com +dnssec
dig example.com DNSKEY
# 检查 DS 记录(在父区域查)
dig example.com DS @a.gtld-servers.net加密 DNS
明文 DNS(UDP 53)可被监听和篡改,加密 DNS 方案:
| 协议 | 端口 | 说明 |
|---|---|---|
| DoT(DNS over TLS) | 853/TCP | 在 TLS 通道内传输 DNS,操作系统级支持(Android 9+、iOS) |
| DoH(DNS over HTTPS) | 443/TCP | DNS 查询封装为 HTTPS,穿越防火墙,浏览器内置支持 |
| DoQ(DNS over QUIC) | 853/UDP | 基于 QUIC,更低延迟,新兴标准 |
配置 DoH(以 Firefox 为例)
设置 → 常规 → 网络设置 → 启用基于 HTTPS 的 DNS
DoH 提供商:
Cloudflare:https://cloudflare-dns.com/dns-query
Google: https://dns.google/dns-query
NextDNS: https://dns.nextdns.io/<profile-id>
Linux 系统级 DoT(systemd-resolved)
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google
DNSOverTLS=yes
DNSSEC=yesSplit-Horizon DNS(分离解析)
同一域名对内网和外网返回不同结果:
内网用户查询 api.example.com → 返回 10.0.0.100(内网地址,直连)
外网用户查询 api.example.com → 返回 1.2.3.4(公网地址,经过 NAT)
实现方式:内网 DNS 服务器(如 BIND 的 view 配置)对内返回私有 IP,权威 DNS 对外返回公网 IP。
Kubernetes 中的 DNS(CoreDNS)
K8s 内每个 Pod 通过集群内 DNS(CoreDNS)解析 Service 名称:
Service 解析规则:
<service-name>.<namespace>.svc.cluster.local
例:redis.default.svc.cluster.local → 10.96.0.100
Pod 间通信:
kubectl exec pod-a -- nslookup redis
→ Server: 10.96.0.10(CoreDNS ClusterIP)
→ Address: 10.96.0.100
/etc/resolv.conf(Pod 内):
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
ndots:5 含义:域名中少于 5 个点时,先拼接 search 域尝试,再作为绝对域名查询。这是 K8s 内频繁 DNS 查询的根源,可通过 FQDN(末尾加 .)或减小 ndots 优化。
常用工具与调试
dig 命令详解
# 基础查询(A 记录)
dig example.com
# 指定记录类型
dig example.com MX
dig example.com TXT
dig example.com NS
# 指定 DNS 服务器查询
dig @8.8.8.8 example.com
# 反向解析(PTR)
dig -x 93.184.216.34
# 追踪完整解析路径(从根开始)
dig +trace example.com
# 精简输出(只看 ANSWER SECTION)
dig +short example.com
# 不使用缓存查询
dig +norecurse @ns1.example.com example.com
# 查看 TTL 剩余时间
dig +ttlunits example.comdig 输出解读
; <<>> DiG 9.16 <<>> example.com A
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 3600 IN A 93.184.216.34
↑TTL ↑类 ↑类型 ↑值
;; Query time: 12 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
nslookup / host
nslookup example.com # 交互或单次查询
nslookup -type=MX example.com
host example.com # 简洁输出
host -t MX example.com修改本机 DNS
# Linux(临时)
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
# Linux(systemd-resolved 持久化)
resolvectl dns eth0 8.8.8.8 1.1.1.1
resolvectl status
# Windows
Set-DnsClientServerAddress -InterfaceAlias "以太网" -ServerAddresses 8.8.8.8,1.1.1.1常见 DNS 问题
| 问题 | 症状 | 排查 |
|---|---|---|
| NXDOMAIN | 域名不存在 | 确认记录已添加、TTL 已过期、拼写正确 |
| SERVFAIL | 服务器故障 | 权威服务器异常或 DNSSEC 验证失败 |
| DNS 缓存污染 | 解析到错误 IP | 刷新缓存、换用 DoH/DoT、检查 DNSSEC |
| DNS 劫持 | 国内特定域名无法解析 | 使用加密 DNS 或指定境外 DNS |
| 解析慢 | 第一次加载慢 | DNS 预解析(<link rel="dns-prefetch">)、提高 TTL |
| ndots 频繁查询 | K8s Pod DNS 延迟 | FQDN 末尾加点,或降低 ndots 值 |
# 清除本机 DNS 缓存
ipconfig /flushdns # Windows
sudo systemd-resolve --flush-caches # Linux (systemd)
sudo killall -HUP mDNSResponder # macOS