DNS解析与CDN加速原理深入解析
一句话概括
DNS(域名系统)将人类可读的域名解析为机器可读的 IP 地址,是整个互联网的”电话簿”;CDN(内容分发网络)则利用全球分布的边缘节点缓存静态资源,使用户从最近的节点获取内容,大幅降低延迟——两者是高性能 Web 应用的底层基础设施。
背景与意义
为什么需要 DNS?
互联网上的每台服务器都有一个 IP 地址(如 142.250.80.46),但人类记不住 32 位的数字。DNS 充当了翻译器:
1
2
3
4
5
你在浏览器输入: https://www.example.com
↓
DNS 解析: www.example.com → 93.184.216.34
↓
浏览器向 93.184.216.34:443 发起 TCP 连接
没有 DNS 的话: 每个人都要背 IP 地址,服务器换了 IP 没人知道。
为什么需要 CDN?
一个典型的页面加载耗时分布:
1
2
3
4
5
6
7
8
9
10
11
没有 CDN 时:
╔══════════════╗
DNS 查询 ║ 50-200ms ║
TCP 连接 ║ 30-100ms ║
TLS 握手 ║ 50-200ms ║ ← 三次网络交互
HTTP 请求 ║ 50-200ms ║
╚══════════════╝
总共:至少 180-700ms 的网络开销
加上全球物理距离:美国用户访问中国的服务器(约 200ms RTT)
→ 加载一个页面至少 1-2 秒
CDN 的做法:把资源缓存到离用户最近的节点,网络延迟从 200ms 降到 20ms。
面试高频信号
DNS 和 CDN 在前端面试中出现的频率越来越高:
- “从输入 URL 到页面显示,DNS 做了什么?”
- “什么是 DNS 缓存?浏览器 DNS 缓存多久?”
- “CDN 的工作原理是什么?”
- “CDN 回源是什么意思?”
概念与定义
DNS 解析流程(完整递归)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
用户在浏览器输入 www.example.com
│
├── 1. 浏览器 DNS 缓存查询(记住之前查过的,通常缓存 60 秒)
│ └─ 未命中 →
├── 2. 操作系统 DNS 缓存查询(系统级别缓存)
│ └─ 未命中 →
├── 3. hosts 文件检查(本地静态映射,优先级最高)
│ └─ 未命中 →
├── 4. 本地 DNS 服务器查询(ISP 或 8.8.8.8 等公共 DNS)
│ ├─ 有缓存 → 返回结果
│ └─ 无缓存 →
│ ├─ 问根服务器("."):"www.example.com 在哪儿?"
│ │ → "去问 .com 的顶级域服务器"
│ ├─ 问 TLD 服务器(".com"):"www.example.com 在哪儿?"
│ │ → "去问 example.com 的权威服务器"
│ └─ 问权威服务器:"www.example.com 在哪儿?"
│ → "答案是 93.184.216.34"
│
└── 5. 返回 IP 地址 → 浏览器发起 TCP 连接
几个关键时间:
- 本地 DNS 缓存:约 1-10ms
- 完整递归解析:约 30-200ms(取决于缓存命中率)
- 全球平均 DNS 解析时间:约 50-80ms
CND 工作原理
1
2
3
4
5
6
7
8
9
10
用户访问 https://cdn.example.com/style.css
│
├── 1. DNS 解析 cdn.example.com
│ └─ 权威 DNS 使用 CNAME 或智能 DNS,返回最近的 CDN 边缘节点 IP
│
├── 2. 用户连接到最近的 CDN 边缘节点(Edge Server)
│ ├─ 节点有缓存 → 直接返回(缓存命中)
│ └─ 节点无缓存 → 回源(去源站拉取资源)→ 缓存到本地 → 返回给用户
│
└── 3. 后续同区域的用户访问同一资源 → 直接从边缘节点返回(缓存命中)
最小示例
1
2
3
4
5
6
7
8
9
10
11
12
13
# DNS 查询命令
# 查看域名解析的 IP
nslookup www.example.com
# 查看完整 DNS 解析路径
dig www.example.com +trace
# 查看 CDN 效果:从不同地区访问
curl -H "Accept-Encoding: gzip" -o /dev/null -s -w 'Time: %{time_total}s\n' \
https://cdn.example.com/file.js
# 查看服务器 IP 所在地区
curl https://ipinfo.io/93.184.216.34
1
2
3
<!-- CDN 加速静态资源 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
核心知识点拆解
知识点 1:DNS 记录类型
| 记录类型 | 含义 | 示例 |
|---|---|---|
| A | 域名 → IPv4 | example.com → 93.184.216.34 |
| AAAA | 域名 → IPv6 | example.com → 2606:2800:220:1:248:1893:25c8:1946 |
| CNAME | 域名 → 另一个域名(别名) | www.example.com → example.cdn.cloudflare.net |
| MX | 邮件服务器 | @ → mail.example.com |
| TXT | 文本记录(SPF/DKIM 验证) | v=spf1 include:_spf.google.com ~all |
| NS | 域名服务器 | example.com → ns1.example.com |
| SOA | 权威信息(管理信息) | 包含主服务器、管理员邮箱、刷新间隔等 |
💡 CDN 的核心:CDN 通过 CNAME 将你的域名指向 CDN 提供的域名,CDN 的权威 DNS 再根据用户 IP 返回最近的边缘节点 IP。
知识点 2:DNS 缓存层级与 TTL
1
2
3
# DNS 响应中的 TTL(Time To Live)
www.example.com. 3600 IN A 93.184.216.34
↑ TTL = 3600 秒(1 小时)
缓存层级:
1
2
3
4
5
6
7
浏览器缓存 ← TTL 范围内命中 ,约 60 秒
↑
操作系统缓存 ← TTL / 2 的规则
↑
本地 DNS 缓存 ← 完全遵守 TTL
↑
根/顶级/权威 ← 中间 DNS 的结果也缓存
TTL 的最佳实践:
- 静态资源(js/css/img):长 TTL(86400 秒 = 1 天)
- 需要切换 CDN 时先降低 TTL:短 TTL(300 秒)
- 切换完成后再恢复长 TTL
知识点 3:CDN 的核心技术
1. 内容路由(智能 DNS)
1
2
3
用户在上海 → DNS 返回上海节点(延迟 5ms)
用户在纽约 → DNS 返回纽约节点(延迟 8ms)
用户在伦敦 → DNS 返回伦敦节点(延迟 7ms)
CDN 根据用户的 EDNS Client Subnet(ECS) 或 DNS 请求的源 IP 判断用户位置,返回最近的边缘节点。
2. 缓存策略
1
2
3
4
# 源站设置的缓存控制头部
Cache-Control: public, max-age=31536000 # CDN 缓存 1 年
Cache-Control: s-maxage=86400 # 仅 CDN 缓存 1 天(覆盖 max-age)
CDN-Cache-Control: public, max-age=3600 # 部分 CDN 支持的专用头部
3. 回源(Origin Pull)
当边缘节点没有缓存时,它会向源站请求资源。回源策略:
1
2
3
4
5
6
7
8
9
回源方式:
├── 直接回源:请求直接转发到源服务器
├── 分层回源:先问上层缓存节点 → 上层未命中 → 问源站
└── 预缓存:提前将热点资源推送到边缘节点
回源优化:
├── 回源超时:5-30 秒
├── 回源重试:失败后重试 2-3 次
└── 回源降级:回源失败时返回过期的缓存内容(stale-while-revalidate)
4. 动态加速(DCDN)
动态内容(API 请求)也可以通过 CDN 加速,核心是优化网络路径而非缓存:
1
2
3
4
用户 → 边缘节点(最近的) → CDN 内部优化路由 → 源站
↑ BGP 优化路由
↑ TCP 优化(多路径)
↑ TLS 复用
知识点 4:前端开发中的 DNS 优化技巧
使用 DNS-Prefetch
1
2
3
4
5
6
7
8
9
10
<head>
<!-- 告诉浏览器提前解析域名 -->
<link rel="dns-prefetch" href="//api.example.com">
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="dns-prefetch" href="//images.example.com">
<!-- preconnect 比 dns-prefetch 更强:DNS + TCP + TLS 预连接 -->
<link rel="preconnect" href="https://api.example.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
</head>
1
2
3
4
5
6
7
8
9
<!-- 浏览器行为对比 -->
dns-prefetch: 只做 DNS 查询
preconnect: DNS 查询 + TCP 连接 + TLS 握手
prefetch: DNS + TCP + TLS + 下载资源(浏览器空闲时)
场景选择:
- 只用 DNS:dns-prefetch(最轻量)
- 确定会访问:preconnect(中度)
- 确定会下载:prefetch(较重)
实战案例
案例一:阿里云 CDN + OSS 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Nginx 源站配置:配合 CDN
server {
listen 443 ssl;
server_name static.example.com;
root /var/www/static;
# 静态资源缓存策略
location ~* \.(js|css|png|jpg|webp|svg|woff2)$ {
expires 365d;
add_header Cache-Control "public, immutable, max-age=31536000";
# 告诉 CDN 文件版本号(用于强制刷新)
add_header X-Cache-Key $uri;
}
# HTML 文件不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, must-revalidate";
}
}
1
2
3
4
5
6
// 前端资源引用加版本号
const ASSET_URL = 'https://cdn.example.com';
const version = 'v1.2.3';
// 版本号在文件名中(利于 CDN 缓存)
const scriptSrc = `${ASSET_URL}/js/app.${version}.min.js`;
案例二:使用 Service Worker 实现离线缓存(CDN 的补充)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Service Worker:CDN 缓存兜底
self.addEventListener('fetch', (event) => {
const request = event.request;
// CDN 资源优先从网络获取(保持最新)
if (request.url.includes('cdn.example.com')) {
event.respondWith(
fetch(request)
.then(response => {
const cloned = response.clone();
caches.open('cdn-cache').then(cache => {
cache.put(request, cloned);
});
return response;
})
.catch(() => {
// CDN 不可用时使用缓存
return caches.match(request);
})
);
}
});
底层原理
DNS 的分布式设计
DNS 系统不是一台服务器,而是一个全球分布式数据库:
1
2
3
4
5
6
7
根 DNS 服务器(13 组,全球 1000+ 实例)
↓(委派)
顶级域(TLD)服务器(.com / .org / .cn 等)
↓(委派)
权威 DNS 服务器(注册商或自建的 DNS 服务器)
↓(记录)
最终域名 → 对应的 IP 地址
🎯 关键 insight:DNS 的”分层”设计让它能承受全球每天数万亿次的查询。没有中心化瓶颈。
CDN 的核心指标
| 指标 | 含义 | 好 | 差 |
|---|---|---|---|
| 命中率 | 缓存命中/总请求 | > 90% | < 70% |
| 回源率 | 未命中/总请求 | < 10% | > 30% |
| P99 延迟 | 99% 请求在 X 毫秒内 | < 50ms | > 200ms |
| 可用性 | 服务正常运行时间 | 99.99%+ | < 99.9% |
高频面试题解析
Q1:从输入 URL 到页面显示,DNS 做了什么?
参考答案:
- 浏览器 DNS 缓存 → 未命中
- 操作系统 DNS 缓存 → 未命中
- hosts 文件检查 → 未命中
- 本地 DNS 服务器发起递归查询:
- 根服务器 → .com 顶级域服务器
- 顶级域服务器 → 域名的权威服务器
- 权威服务器 → 返回 IP
- 结果缓存到各级 DNS,返回 IP 给浏览器
- 浏览器开始 TCP 连接
Q2:什么是 CDN 回源?什么情况下会回源?
参考答案: 回源指边缘节点没有缓存时,向后端源站请求资源的过程。触发的场景:
- 资源从未被请求过(冷启动)
- TTL 过期(缓存失效)
- 源站主动刷新了缓存(手动清除)
- 动态内容不缓存
回源是会增加延迟的,所以高命中率是 CDN 的核心指标。
Q3:dns-prefetch 和 preconnect 的区别?
参考答案:
dns-prefetch:只做 DNS 解析(最轻量)preconnect:DNS 解析 + TCP 连接 + TLS 握手(更重但更彻底)- 高效做法:对一定会访问的域名用 preconnect,可能访问的域名用 dns-prefetch
Q4:CDN 缓存刷新(Purge)后,用户什么时候能看到新版本?
参考答案: 取决于 TTL:
- TTL=1小时:最长1小时后所有用户都能获取新版本
- 可通过强制刷新(URL 加版本号)绕过 CDN 缓存
- 也可通过 CDN 管理面板手动清除特定 URL 的缓存
总结与扩展
核心要点
- DNS = 分层分布式数据库,域名 → IP 的翻译服务
- CDN = 全球分布式缓存 + 智能路由,把内容送到用户近端
- DNS 缓存 有浏览器/操作系统/本地 DNS 三层
- CDN 核心:缓存命中率、回源策略、智能 DNS 路由
- 前端优化:dns-prefetch / preconnect 预解析域名
延伸学习方向
- HTTP/3 (QUIC):基于 UDP 的传输协议,CDN 加速效果的进一步提升
- Anycast:CDN 节点通过同一个 IP 对外服务(BGP Anycast)
- Edge Computing:在 CDN 边缘节点执行 JS 代码(Cloudflare Workers / AWS Lambda@Edge)
- DoH / DoT:加密 DNS 查询(DNS over HTTPS / DNS over TLS)