计算机网络:什么是 CDN?为什么它可以做缓存?
结论:CDN(Content Delivery Network,内容分发网络)把内容副本提前放到离用户更近的边缘节点,再用调度把请求引到最近节点, 从而降低 RTT、分担源站带宽。它能做缓存,是因为 HTTP 本身就定义了可缓存语义,而 CDN 拿到的恰好是"可复用的静态响应"。
1. 一次请求怎么走到边缘
用户 --① 访问 www.example.com--> 本地 DNS
本地 DNS --② 递归查询--> 权威 DNS(返回 CNAME: www.example.com.cdn.net)
本地 DNS --③ 查询 cdn.net--> GSLB 按地域/运营商/负载选节点
本地 DNS --④ 返回边缘节点 IP--> 用户
用户 --⑤ 直连边缘节点(通常 10~30 ms)--> 边缘节点
边缘节点 --⑥ 未命中则回源--> 源站,拉取后缓存
调度层是 CDN 的一半:DNS 调度(CNAME + GSLB,按 EDNS Client Subnet 判断用户位置)、Anycast(同一 IP 全球广播, 由路由把人带到最近节点),以及 HTTP 302 调度(少见但存在)。
另一半是缓存层:边缘节点命中就直接返回,不命中才回源,并把响应按缓存键存下来给下一个人用。
2. 缓存能不能做,看响应头
| 响应头 | 语义 | 边缘节点行为 |
|---|---|---|
Cache-Control: max-age=3600 | 1 小时内新鲜 | 缓存 1 小时 |
Cache-Control: s-maxage=600 | 只对共享缓存生效 | 覆盖 max-age,仅 CDN 用 |
Cache-Control: no-cache | 可存,但每次要回源验证 | 存,但带 If-None-Match 回源 |
Cache-Control: no-store | 任何缓存都不得保存 | 直接透传,不落盘 |
Cache-Control: private | 仅终端浏览器可缓存 | 边缘不缓存 |
ETag / Last-Modified | 内容指纹 / 修改时间 | 用于协商,命中返回 304 |
Vary: Accept-Encoding | 按编码分副本 | 缓存键增加该维度 |
Set-Cookie | 会话相关 | 一般导致不缓存 |
所以"为什么能缓存"的答案很朴素:HTTP 用 Cache-Control 与验证器把"能不能存、能存多久、怎么验"都标准化了,
CDN 只是把这个规范执行到离用户最近的机器上。
3. 用 nginx 搭一个迷你边缘节点
proxy_cache_path /data/cache levels=1:2 keys_zone=edge:100m
max_size=10g inactive=2h use_temp_path=off;
server {
listen 80;
server_name edge.example.com;
location /static/ {
proxy_cache edge;
proxy_cache_key $scheme$host$request_uri;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502;
proxy_cache_lock on; # 同一 key 只放一个回源请求
proxy_cache_background_update on; # 过期后先返回旧内容,后台刷新
add_header X-Cache-Status $upstream_cache_status; # HIT / MISS / STALE / EXPIRED
proxy_pass http://origin_pool;
}
location /api/ {
proxy_cache off; # 动态接口默认不缓存
proxy_pass http://origin_pool;
}
}
X-Cache-Status 是排查命中率的关键:大量 MISS 时先看是不是缓存键里混进了随机参数或 Cookie。
4. 常见追问
Q:发版后怎么让 CDN 立刻生效?
两条路:文件名带内容哈希(app.3f9c2a.js)配合长缓存,发版即换 URL,天然绕过旧副本;
或者调 CDN 的刷新接口按 URL / 目录清理。前者是工程首选,后者用于入口 HTML 这类不能改名的资源。
Q:命中率低怎么排查?
依次看:缓存键是否含随机 query / 时间戳;是否透传了 Cookie 导致不缓存;TTL 是否过短;
是否大量 Range 请求;回源是否因为 Vary 维度爆炸。把 X-Cache-Status 打点统计,比猜快得多。
Q:动态 API 能放 CDN 吗? 可以,但要精确:短 TTL(如 1~5 秒)、按用户或租户分键、只缓存幂等的 GET; 私有内容用签名 URL + 短过期时间,避免把 A 用户的数据发给 B 用户。
Q:CDN 只是"缓存"吗? 不。它还做 TLS 终止与证书管理、HTTP/2 与 HTTP/3 接入、gzip / brotli 压缩、图片转码、 回源长连接复用、WAF 与 DDoS 清洗。缓存只是最容易被感知的那部分。
Q:CDN 会不会缓存错误页? 会,如果响应头允许。所以通常给 5xx 设很短的 TTL 或不缓存,只对 404 设 1 分钟这类短缓存, 避免一次源站故障被放大成持续几分钟的全站错误。
Q:为什么用户到边缘快了,整体就快了? 因为延迟主要由 RTT 与丢包决定。边缘把"跨运营商、跨地域的长肥管道"换成"同城短链路", TCP 慢启动、TLS 握手、丢包重传的代价都随之下降,收益远不止带宽。
小结
CDN = 调度 + 缓存 + 回源 + 传输优化。调度决定"去哪台",缓存决定"要不要回源",
而能否缓存由源站的 Cache-Control、验证器与 Vary 说了算。
工程上抓住三点:静态资源带哈希长缓存、入口 HTML 短缓存可刷新、用 X-Cache-Status 把命中率变成可观测指标。