Language:Chinese VersionEnglish Version

你曾经学过DNS。然后除了”它会传播”之外,你忘了一切。

DNS是那些每个开发者都会遇到的技术,很少有人真正理解,大多数人通过等待48小时并希望问题能自行解决来进行故障排除。”只需等待传播”的建议通常是错误的—DNS更改不会像波浪一样传播。它们根据TTL值在不同时间从缓存中过期。当你调试为什么一半用户看到旧站点而另一半看到新站点时,这种区别很重要。

这不是网络教科书的章节。这是后端开发者在设置域名、调试连接问题或试图弄清楚为什么他们的邮件被归类为垃圾邮件时实际需要的实用DNS知识。

DNS解析实际如何工作

当用户在浏览器中输入api.example.com时,实际发生的情况如下:

  1. 浏览器缓存:浏览器首先检查自己的DNS缓存。Chrome默认缓存DNS条目60秒。
  2. 操作系统解析器:如果未缓存,操作系统解析器会检查其缓存(在Linux上由systemd-resolved管理,在macOS上由mDNSResponder管理)。
  3. 递归解析器:如果本地没有缓存,查询会发送到递归解析器(你的ISP,或8.8.8.8,或1.1.1.1)。这是执行实际工作的服务器。
  4. 根域名服务器:递归解析器询问根域名服务器”谁处理.com?”
  5. 顶级域名服务器:根域名服务器响应.com的TLD域名服务器。递归解析器询问它们”谁处理example.com?”
  6. 权威域名服务器:TLD域名服务器响应example.com的权威域名服务器。递归解析器询问它们”api.example.com的地址是什么?”
  7. 答案:权威域名服务器返回IP地址,递归解析器根据指定的TTL值缓存它。
# 使用dig +trace观看完整的解析链
$ dig +trace api.example.com

; <<>> DiG 9.18.18 <<>> +trace api.example.com
;; global options: +cmd
.                 86400   IN  NS  a.root-servers.net.
.                 86400   IN  NS  b.root-servers.net.
;; 从 127.0.0.53#53 收到 239 字节

com.              172800  IN  NS  a.gtld-servers.net.
com.              172800  IN  NS  b.gtld-servers.net.
;; 从 198.41.0.4#53(a.root-servers.net) 收到 836 字节

example.com.      172800  IN  NS  ns1.example.com.
example.com.      172800  IN  NS  ns2.example.com.
;; 从 192.5.6.30#53(a.gtld-servers.net) 收到 286 字节

api.example.com.  300     IN  A   93.184.216.34
;; 从 93.184.216.34#53(ns1.example.com) 收到 62 字节

真正重要的记录类型

A和AAAA记录

A 记录将主机名映射到 IPv4 地址。AAAA 记录映射到 IPv6。这些是最基础的 DNS 记录:

# A 记录:主机名 -> IPv4
api.example.com.    300    IN    A    93.184.216.34

# AAAA 记录:主机名 -> IPv6
api.example.com.    300    IN    AAAA    2606:2800:220:1:248:1893:25c8:1946

# 可以为同一主机名设置多个 A 记录(轮询 DNS)
api.example.com.    300    IN    A    93.184.216.34
api.example.com.    300    IN    A    93.184.216.35
# 客户端通常会在这些地址之间轮换

CNAME 记录

CNAME (规范名称) 记录从一个主机名创建到另一个主机名的别名。它们是最容易被误解的记录类型:

# CNAME:"www" 是 "example.com" 的别名
www.example.com.    3600    IN    CNAME    example.com.

# 常见用途:指向 CDN 或负载均衡器
app.example.com.    300     IN    CNAME    d123456.cloudfront.net.

# 关键规则:CNAME 记录不能与任何其他记录类型同时存在于同一名称下。
# 这意味着你不能在你的根域名(example.com)上放置 CNAME,
# 因为根域名已经有 SOA 和 NS 记录。

# 这是无效的:
# example.com.    300    IN    CNAME    myapp.herokuapp.com.  ← 错误
# example.com.    300    IN    SOA      ...                    ← 冲突

# 解决方案:使用 ALIAS/ANAME 记录(特定于提供商)或
# Cloudflare 的 CNAME 扁平化

MX 记录

MX (邮件交换) 记录告诉其他邮件服务器将邮件发送到您域名的位置:

# 带优先级的 MX 记录(数字越小优先级越高)
example.com.    3600    IN    MX    10    mail1.example.com.
example.com.    3600    IN    MX    20    mail2.example.com.
example.com.    3600    IN    MX    30    mail-backup.example.com.

# 如果你使用 Google Workspace:
example.com.    3600    IN    MX    1     aspmx.l.google.com.
example.com.    3600    IN    MX    5     alt1.aspmx.l.google.com.
example.com.    3600    IN    MX    5     alt2.aspmx.l.google.com.
example.com.    3600    IN    MX    10    alt3.aspmx.l.google.com.
example.com.    3600    IN    MX    10    alt4.aspmx.l.google.com.

TXT 记录

TXT 记录存储任意文本,用于域名验证、邮件认证以及各种域名所有权证明:

# SPF 记录:哪些服务器可以为您域名发送邮件
example.com.    3600    IN    TXT    "v=spf1 include:_spf.google.com ~all"

# DKIM 记录:邮件签名的公钥
google._domainkey.example.com.    3600    IN    TXT    "v=DKIM1; k=rsa; p=MIIBIjANBg..."

# DMARC 记录:邮件认证策略
_dmarc.example.com.    3600    IN    TXT    "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"

# 域名验证(Google、Microsoft 等)
example.com.    3600    IN    TXT    "google-site-verification=abc123..."

# Let's Encrypt DNS-01 挑战
_acme-challenge.example.com.    300    IN    TXT    "gfj9Xq...Rg85nM"

SRV 记录

SRV 记录指定特定服务的主机和端口。它们被 SIP、XMPP 和 LDAP 等协议使用,并且越来越多地被现代服务发现系统采用:

# 格式:_服务._协议.域名.  TTL  IN  SRV  优先级 权重 端口 目标
_sip._tcp.example.com.    3600    IN    SRV    10 60 5060 sipserver.example.com.
_xmpp._tcp.example.com.   3600    IN    SRV    10 0  5222 xmpp.example.com.

TTL:您一直忽略的最重要的数字

TTL(生存时间)是 DNS 记录可以被解析器缓存的秒数。它是 DNS 中最重要的操作参数,而设置错误是大多数 DNS 相关问题的根源。

# 常见的 TTL 值及其使用场景
# 300  (5 分钟) - 您频繁更改或需要快速故障转移的记录
# 3600 (1 小时) - 偶尔更改的标准记录
# 86400 (1 天) - 很少更改的记录(NS 记录、MX 记录)

# 迁移的黄金法则:
# 1. 更改前:将 TTL 降低到 300(等待旧 TTL 过期)
# 2. 进行更改
# 3. 验证一切正常
# 4. 更改后:将 TTL 提高回 3600+

# 迁移到新服务器的时间表示例:
# 第 0 天:将 TTL 从 3600 更改为 300
# 第 1 天:(等待 24 小时让旧的 3600 TTL 在各处过期)
# 第 2 天:将 A 记录更改为新 IP
# 第 2 天+5 分钟:大多数用户看到新 IP(300s TTL)
# 第 3 天:验证一切正常,将 TTL 提高回 3600

像专业人士一样调试 DNS

基本命令

# 基本查询
$ dig api.example.com
# 返回:A记录、TTL、权威服务器

# 查询特定记录类型
$ dig api.example.com AAAA
$ dig example.com MX
$ dig example.com TXT
$ dig _dmarc.example.com TXT

# 直接查询特定名称服务器(绕过缓存)
$ dig @ns1.example.com api.example.com

# 查询公共解析器(检查世界其他地方看到的内容)
$ dig @8.8.8.8 api.example.com
$ dig @1.1.1.1 api.example.com

# 简短输出(仅答案)
$ dig +short api.example.com
93.184.216.34

# 完整跟踪(查看整个解析链)
$ dig +trace api.example.com

# 检查特定解析器是否有过期数据
$ dig @8.8.8.8 +short api.example.com
$ dig @1.1.1.1 +short api.example.com
# 如果这些结果不同,说明某个解析器缓存了旧值

# 反向DNS查询
$ dig -x 93.184.216.34

# 检查SOA记录(有助于调试区域问题)
$ dig example.com SOA

常见调试场景

# 场景:"我更改了DNS记录但没有任何变化"
# 步骤1:检查权威服务器返回的内容
$ dig @ns1.your-provider.com your-domain.com A
# 如果显示旧值,说明您的更改未正确保存。
# 如果显示新值,这是缓存问题。

# 步骤2:检查旧记录上的TTL
# 旧记录的TTL为86400(24小时)。即使您更改了它,
# 缓存了旧值的解析器仍会保留它最多24小时。

# 场景:"域名迁移后邮件无法工作"
# 检查MX记录
$ dig example.com MX +short
10 mail.example.com.
# 然后检查MX目标是否解析
$ dig mail.example.com A +short
93.184.216.34
# 然后检查SPF
$ dig example.com TXT | grep spf
# 然后检查DMARC
$ dig _dmarc.example.com TXT

现代基础设施中的DNS

内部DNS和服务发现

在Kubernetes和Docker环境中,内部DNS处理服务发现:

# Kubernetes DNS格式:
# ..svc.cluster.local

# 从pod内部,您可以解析:
$ dig payment-service.production.svc.cluster.local
# 返回payment-service的ClusterIP

# Headless服务返回单个pod IP:
$ dig payment-service-headless.production.svc.cluster.local
# 返回支持该服务的每个pod的A记录

# CoreDNS是Kubernetes中的默认DNS服务器
# 其配置位于ConfigMap中:
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }

基于DNS的负载均衡

DNS 可以将流量分配到多个服务器,但与真正的负载均衡器相比,它有显著的局限性:

# 轮询DNS:多个A记录
api.example.com.    30    IN    A    10.0.1.1
api.example.com.    30    IN    A    10.0.1.2
api.example.com.    30    IN    A    10.0.1.3

# 局限性:
# - 没有健康检查(会返回已失效的服务器)
# - 客户端可能缓存并固定使用一个IP
# - 没有会话亲和性
# - 没有加权分配(没有提供商支持)

# 更好的做法:使用DNS进行地理路由,使用负载均衡器进行服务器选择
# Route53地理位置路由、Cloudflare负载均衡等

DNS over HTTPS (DoH) 和 DNS over TLS (DoT)

传统的DNS查询以明文通过UDP发送,这意味着网络路径上的任何人都可以看到您解析的域名。DoH和DoT加密DNS查询:

# 使用curl通过HTTPS查询DNS
$ curl -s -H 'accept: application/dns-json' 
  'https://1.1.1.1/dns-query?name=example.com&type=A' | jq .

{
  "Status": 0,
  "Answer": [
    {
      "name": "example.com",
      "type": 1,
      "TTL": 3600,
      "data": "93.184.216.34"
    }
  ]
}

每个新项目的DNS检查清单

  1. 设置合理的TTL值: 对于可能变化的记录(A、AAAA)使用300-600,对于稳定的记录(MX、NS)使用3600+。
  2. 配置邮件认证: SPF、DKIM和DMARC记录。没有这些,您的邮件会被发送到垃圾邮件文件夹。
  3. 使用至少两个名称服务器: 最好来自不同的提供商以实现冗余。
  4. 添加CAA记录: 指定哪些证书颁发机构可以为您的域名颁发证书。
  5. 设置监控: 从多个地理位置监控DNS解析。
  6. 记录您的DNS记录: 为所有DNS记录保留一个真实来源文档(或使用基础设施即代码)。
  7. 迁移前降低TTL值: 在进行更改前,至少提前一个完整的TTL周期降低TTL值。

DNS不是性感的基础设施。没有人会写博客文章谈论他们美丽的DNS配置。但DNS故障是您会遇到的最明显且最令人困惑的停机之一,因为它们会根据缓存、地理位置和解析器行为对不同用户表现出不同的症状。理解DNS的实际工作原理——而不仅仅是知道如何在提供商的控制面板中添加A记录——是在五分钟内解决问题与花费三小时确信服务器已损坏(实际上只是过期的CNAME)之间的区别。

By Michael Sun

Founder and Editor-in-Chief of NovVista. Software engineer with hands-on experience in cloud infrastructure, full-stack development, and DevOps. Writes about AI tools, developer workflows, server architecture, and the practical side of technology. Based in China.

Leave a Reply

Your email address will not be published. Required fields are marked *

You missed