CDN 接入与运营实战

目录

本文是 CDN 系列的实战篇,使用一个公开内容站点作为贯穿案例:前端构建产物带内容哈希,HTML 入口会随发布更新,登录 API 不进入共享缓存。目标是把接入、更新和排障落实成可验证的操作。内部机制见《CDN 技术体系:从分发原理到工程落地》,选型与全球化取舍见《内容分发体系设计:CDN 架构决策与全球化落地》。

接入前先写清内容策略

CDN 能减少重复获取和远距离传输,但长尾内容、刚发布的对象和动态接口不会拥有同样的命中率。不要先规定“所有静态资源必须超过 95%”,再把任何偏差都归因于配置错误。

本例内容 缓存策略起点 更新方式
/assets/app.{hash}.js 等不可变资源 长新鲜期、immutable 发布新 URL,保留旧文件
/index.html no-cache 或满足更新目标的短 TTL 更新入口,必要时精确失效
公开版本化图片与下载文件 按版本长缓存 新对象使用新路径
允许短暂陈旧的公开查询 短 TTL,按业务决定是否 SWR 验证、过期或失效
登录 API、私有响应 默认 no-store,绕过共享缓存 每次请求保持正确身份与权限

带 Cookie 不必然意味着响应不可共享,例如纯静态资源可能与 Cookie 无关;没有 Cookie 也不能证明资源公开。初始接入可以采用保守的登录绕过策略,再逐项开放经过验证的例外。

no-cache 允许存储,但重用前需要验证;验证可能返回 304,也可能返回新的正文,并不等于“不回源”。no-store 阻止本次响应被缓存,不能清除此前已存储的所有旧副本。HTTP 缓存规范

选择具体服务与网络,不按品牌猜行为

选型时携带实际的地域流量、文件大小和功能要求,比较同一负载下的体验、回源、合同报价和运维接口。主流供应商可能提供多个不同套餐或网络,不能用一个起步价决定总体成本。

尤其要区分全球服务与中国大陆服务:Cloudflare 的 China Network 和 CloudFront 中国服务有各自的开通与运营条件,“这两个品牌在大陆没有节点”的说法不准确。Cloudflare China Network、CloudFront 中国服务

使用大陆加速服务时按服务商要求核对域名备案等接入条件;全球化的数据处理边界则应另行核对,不能靠节点地图或 GeoDNS 自动满足。架构篇已说明这些区别,接入时要把选择落实到具体账户、网络和合同。

配置域名、回源与 TLS

先在 CDN 添加业务域名并完成所有权验证,获得服务商分配的目标,再修改 DNS。标准 CNAME 不能与根域名必需记录并存;需要根域名加速时,使用 DNS 服务商明确支持的别名或展平能力。

源站地址、HTTP Host 和 TLS SNI 是三个相关但不同的配置:

项目 本例 用途
访问域名 static.example.com 用户请求和边缘证书
回源地址 origin.example.com CDN 连接源站
回源 Host 由源站虚拟主机配置确定 选择正确站点
回源 SNI 与受信任证书名称匹配 TLS 握手与证书校验

源站地址不能解析回同一 CDN 入口而形成循环。用户到 CDN、CDN 到源站分别建立 TLS;后者需要校验证书和名称,不能因为使用内网或自签证书就直接关闭验证,应配置受信任证书链。

提前降低 DNS TTL 可以缩短一部分缓存等待,但不会立即清除已经缓存的旧记录、长连接或应用连接池。切换期间应保留旧链路,观察真实流量收敛。

缓存规则与源站响应头一起验证

下面是 Nginx 的配置片段,假设 /assets/ 只包含不可变且公开的版本化文件,API 后端监听本机 9000 端口。目录、端口与 TLS 需按部署环境补齐:

server {
    listen 8080;
    server_name origin.example.com;
    root /srv/content-site;

    location ^~ /assets/ {
        try_files $uri =404;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location = /index.html {
        try_files $uri =404;
        add_header Cache-Control "no-cache";
        etag on;
    }

    location ^~ /api/ {
        proxy_pass http://127.0.0.1:9000;
        proxy_hide_header Cache-Control;
        add_header Cache-Control "no-store" always;
    }
}

这里使用固定目录隔离公开静态资源,没有按所有 .js 或 .jpg 后缀一律长缓存。API 用 ^~ 防止后续增加的正则 location 抢走路径。示例统一 API 的 Cache-Control;真实项目若由应用输出细粒度策略,应保留应用的权威配置,避免重复或矛盾响应头。

CDN 控制台规则可能覆盖源站头,最小 TTL、缓存 eligibility、边缘函数也会影响结果。不存在统一的“源站头永远优先”规则,必须检查所用产品。接入后分别验证静态资源、HTML、API、错误响应及带认证请求。

只忽略确实不影响响应的参数

追踪参数可以造成不必要的缓存分裂,但宽度、语言、版本、签名等参数可能改变响应或访问权限。移除参数前检查源站行为,再确认缓存键和回源参数是否分别配置。

不能把 v 从缓存键去掉,却仍依赖 ?v=2 更新版本。签名参数是否进入缓存键也不等于是否执行鉴权:即使复用同一个媒体对象,每次私有访问仍需要正确授权。

跨域按资源用途设置

跨域图片展示、JavaScript 读取响应、模块脚本和字体的要求不同。不能因为静态域名不同就为所有内容盲目反射 Origin。

公开且无凭据的资源可以按需要返回固定的 Access-Control-Allow-Origin: *。按白名单返回具体 Origin 时,要让缓存正确区分相应响应,核对 Vary: Origin 或厂商缓存策略;带凭据的请求还要匹配凭据规则。CORS 不替代资源访问鉴权。

发布:先放新文件,再更新入口

发布先验证版本化资源,再更新入口并检查用户链路

一个可恢复的发布流程包含:

  1. 构建并记录版本与资源清单,检查所有引用存在
  2. 上传不可变资源,确认状态码、类型与内容摘要正确
  3. 更新 HTML 等入口,避免入口引用尚未准备好的文件
  4. 对需要更新的可变 URL 提交精确 Purge,记录厂商任务 ID
  5. 从目标地区检查入口版本与关键资源,失败时按已验证方案回退
  6. 按保留策略清理旧资源,不在发布新入口时立即删除旧文件

版本化文件不需要为内容变更清除旧 URL,但入口更新仍需要新鲜度策略。Purge 通常只影响对应 CDN,不能强制清除浏览器缓存或让已打开页面切换代码。

全站 Purge 会增加冷缓存流量,影响程度取决于原命中、对象热度、请求合并和源站容量。不要用固定“准备五到十倍容量”代替计算;优先缩小失效范围,并按产品能力在失效完成后受控预热。提前预热随后又清空,并不能保住新缓存。

多 CDN 场景下记录每家提交、完成、失败和验证状态,一家成功不能标记整体成功。Purge 服务也需要鉴权、范围校验、重试和审计,不能接收任意外部 URL 或任意回调地址就直接执行。

验证:状态码、内容和缓存状态分别看

以下命令中的域名是示例,需替换成已授权测试的目标。优先使用 GET 观察真实响应;HEAD 可以辅助检查,但其缓存和回源行为不一定完全相同。

curl --fail --silent --show-error --dump-header - --output /dev/null \
  https://static.example.com/assets/app.examplehash.js

检查正确对象是否为 200、类型是否正确、Cache-Control 是否符合策略,再结合供应商的缓存状态头和 Age 判断。Cloudflare、CloudFront 等状态字段不同;没有某一个特定头,不等于一定没走 CDN。

切换 DNS 前可以用 --resolve 保持 URL 域名、Host 与 SNI,同时连接选定的测试地址。下面使用文档保留地址,必须换成该服务真实返回且允许测试的地址:

curl --fail --silent --show-error \
  --resolve static.example.com:443:192.0.2.10 \
  --dump-header - --output /dev/null \
  https://static.example.com/index.html

这验证的是当前发起位置到该地址的路径。给不同 IP 贴上“北京、上海”的标签,不会把本机请求变成真正的多地拨测;Anycast 地址还可能路由到不同实际节点。

检查 需要确认的结果
新入口 正文中的发布版本及引用符合本次发布
新资源 内容摘要匹配,不只是返回 200
缓存复用 同键重复请求的缓存状态符合产品策略
认证隔离 不同账户、匿名与退出后的响应不会串用
Range 支持时返回正确的 206 与 Content-Range
错误响应 404/5xx 不被错误设置成长时间公开缓存
回退 旧入口所需资源仍可获取,业务数据兼容

ETag 可以作为版本线索,但不应在所有对象存储或压缩路径中都当作文件 MD5。必要时下载正文验证自己的内容摘要或发布标识。

全球化分流需要真正支持地域策略的 DNS 或流量管理产品。普通 Cloudflare DNS 记录不能通过写上“仅 CN”就变成地域路由;Load Balancing 的 steering policies 是另一项能力,还需核对模式、套餐与目标接入限制。Cloudflare 流量调度策略

日常运营:按异常类型选择检查

症状 优先检查 不能直接得出的结论
命中率下降 新内容比例、缓存键、TTL、规则与失效记录 一定是 TTL 太短
用户看到旧内容 浏览器、Service Worker、CDN、源站版本 Purge 提交成功就应全网更新
某地访问慢 解析、建连、HIT/MISS、运营商与终端 一定是该地没有节点
回源失败 DNS、SNI、证书、Host、网络和源站日志 一定是源站应用故障
源站流量突增 失效、冷缓存、新热点、绕过与攻击 一定是有人全站 Purge

缓存合并、回源并发限制和允许范围内的 stale 响应可以缓解冲击,但是否生效必须事先配置并验证。源站返回 503 本身不会让 CDN 自动具备旧响应兜底;如果对象从未缓存、旧值已被硬删除,或者策略不允许陈旧响应,就没有可以复用的内容。

监控至少区分请求命中率、字节命中率、回源请求与字节量、用户延迟、错误率和费用。告警阈值围绕正常基线、源站余量和业务目标设置,不把统一百分比套到所有站点。

成本优化也要核对口径:字节命中率从 90% 提升到 95%,在相同交付量和其他简化条件下可将未命中字节减半,但不会把 CDN 向用户交付的流量减半。图片格式、裁剪和压缩是否有效,应以代表性素材的体积与质量比较为准。

接入完成的标志,是团队知道每类内容如何缓存、怎样更新、怎样判断当前版本,以及异常时先查哪条链路。把这些动作纳入发布记录和持续观测,CDN 才能成为可维护的基础设施。

评论