CDN(内容分发网络)知识总结

文章目录

    • [一、CDN 概述](#一、CDN 概述)
      • [1.1 CDN 解决什么问题](#1.1 CDN 解决什么问题)
      • [1.2 基本工作流程](#1.2 基本工作流程)
      • [1.3 核心架构](#1.3 核心架构)
      • [1.4 缓存机制](#1.4 缓存机制)
      • [1.5 静态加速 vs 动态加速](#1.5 静态加速 vs 动态加速)
      • [1.6 路由与协议优化](#1.6 路由与协议优化)
      • [1.7 常见应用场景](#1.7 常见应用场景)
    • [二、什么情况下可以不上 CDN](#二、什么情况下可以不上 CDN)
      • [2.1 可以不上 CDN 的情况](#2.1 可以不上 CDN 的情况)
      • [2.2 即使都在同一城市,CDN 仍可能有价值](#2.2 即使都在同一城市,CDN 仍可能有价值)
      • [2.4 决策速查表](#2.4 决策速查表)
    • [三、CDN 多节点缓存不一致问题](#三、CDN 多节点缓存不一致问题)
      • [3.1 为什么会不一致?](#3.1 为什么会不一致?)
      • [3.2 常见触发场景](#3.2 常见触发场景)
      • [3.3 解决方案](#3.3 解决方案)
      • [3.4 实际工程中最常用的做法](#3.4 实际工程中最常用的做法)
    • [四、CDN 调度系统](#四、CDN 调度系统)
      • [4.1 谁在提供调度服务?](#4.1 谁在提供调度服务?)
      • [4.2 调度系统具体做什么?](#4.2 调度系统具体做什么?)
      • [4.3 一句话理解](#4.3 一句话理解)
    • [五、访问 CDN 的网络链路](#五、访问 CDN 的网络链路)
      • [5.1 一次完整的 CDN 访问链路](#5.1 一次完整的 CDN 访问链路)
      • [5.2 回源链路可能有层级](#5.2 回源链路可能有层级)
      • [5.3 动态请求链路略有不同](#5.3 动态请求链路略有不同)
      • [5.4 一句话串起来](#5.4 一句话串起来)
    • [六、如何判断 CDN 是否生效](#六、如何判断 CDN 是否生效)
      • [6.1 第一步:看 DNS ------ 请求是否走到了 CDN](#6.1 第一步:看 DNS —— 请求是否走到了 CDN)
      • [6.2 第二步:看响应头 ------ 资源是否命中 CDN 缓存](#6.2 第二步:看响应头 —— 资源是否命中 CDN 缓存)
      • [6.3 第三步:看 Remote Address ------ 是否连接到 CDN 节点](#6.3 第三步:看 Remote Address —— 是否连接到 CDN 节点)
      • [6.4 分层判断 CDN 是否真正"起作用"](#6.4 分层判断 CDN 是否真正"起作用")
      • [6.5 实用排查顺序](#6.5 实用排查顺序)
    • [七、CDN 缓存与浏览器缓存的关系](#七、CDN 缓存与浏览器缓存的关系)
      • [7.1 强缓存 vs 协商缓存](#7.1 强缓存 vs 协商缓存)
      • [7.2 三级缓存判断流程](#7.2 三级缓存判断流程)
      • [7.3 关键结论](#7.3 关键结论)
    • [八、防盗链与 URL 鉴权](#八、防盗链与 URL 鉴权)
      • [8.1 常见防护方式对比](#8.1 常见防护方式对比)
      • [8.2 URL 鉴权的签名思路](#8.2 URL 鉴权的签名思路)
    • 九、回源细节与常见坑
      • [9.1 回源 HOST](#9.1 回源 HOST)
      • [9.2 回源协议](#9.2 回源协议)
      • [9.3 Range 回源(分片缓存)](#9.3 Range 回源(分片缓存))
      • [9.4 获取用户真实 IP](#9.4 获取用户真实 IP)
    • 十、命中率、监控与计费
      • [10.1 命中率怎么算](#10.1 命中率怎么算)
      • [10.2 关键监控指标](#10.2 关键监控指标)
      • [10.3 常见计费方式](#10.3 常见计费方式)
    • [十一、接入 CDN 的标准流程](#十一、接入 CDN 的标准流程)
    • 十二、常见问题排查(FAQ)

一、CDN 概述

CDN(Content Delivery Network,内容分发网络)本质是在互联网上多加一层分布式节点,把内容缓存到离用户更近的地方,让用户就近获取,从而降低延迟、减轻源站压力。

1.1 CDN 解决什么问题

  • 降低延迟:用户不再每次都访问远端源站,而是访问最近的边缘节点。
  • 减轻源站压力:图片、CSS、JS、视频等静态资源由边缘节点承担,源站只需处理回源和动态请求。
  • 提升可用性:多节点冗余,某个节点故障时可以切换到其他节点。
  • 改善跨运营商/跨地域访问:比如电信用户访问联通源站时,可通过同运营商边缘节点加速。

1.2 基本工作流程

  1. 用户访问域名。
  2. DNS 解析被指向 CDN 调度系统。
  3. 调度系统根据用户 IP、地域、运营商、节点负载等选择最优边缘节点。
  4. 边缘节点如果有有效缓存,直接返回。
  5. 如果没有缓存或缓存过期,就回源站拉取内容,再返回给用户并缓存。

#mermaid-svg-XWRw8PH5VJiYbcZM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XWRw8PH5VJiYbcZM .error-icon{fill:#552222;}#mermaid-svg-XWRw8PH5VJiYbcZM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XWRw8PH5VJiYbcZM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XWRw8PH5VJiYbcZM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XWRw8PH5VJiYbcZM .marker.cross{stroke:#333333;}#mermaid-svg-XWRw8PH5VJiYbcZM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XWRw8PH5VJiYbcZM p{margin:0;}#mermaid-svg-XWRw8PH5VJiYbcZM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster-label text{fill:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster-label span{color:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster-label span p{background-color:transparent;}#mermaid-svg-XWRw8PH5VJiYbcZM .label text,#mermaid-svg-XWRw8PH5VJiYbcZM span{fill:#333;color:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM .node rect,#mermaid-svg-XWRw8PH5VJiYbcZM .node circle,#mermaid-svg-XWRw8PH5VJiYbcZM .node ellipse,#mermaid-svg-XWRw8PH5VJiYbcZM .node polygon,#mermaid-svg-XWRw8PH5VJiYbcZM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XWRw8PH5VJiYbcZM .rough-node .label text,#mermaid-svg-XWRw8PH5VJiYbcZM .node .label text,#mermaid-svg-XWRw8PH5VJiYbcZM .image-shape .label,#mermaid-svg-XWRw8PH5VJiYbcZM .icon-shape .label{text-anchor:middle;}#mermaid-svg-XWRw8PH5VJiYbcZM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XWRw8PH5VJiYbcZM .rough-node .label,#mermaid-svg-XWRw8PH5VJiYbcZM .node .label,#mermaid-svg-XWRw8PH5VJiYbcZM .image-shape .label,#mermaid-svg-XWRw8PH5VJiYbcZM .icon-shape .label{text-align:center;}#mermaid-svg-XWRw8PH5VJiYbcZM .node.clickable{cursor:pointer;}#mermaid-svg-XWRw8PH5VJiYbcZM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XWRw8PH5VJiYbcZM .arrowheadPath{fill:#333333;}#mermaid-svg-XWRw8PH5VJiYbcZM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XWRw8PH5VJiYbcZM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XWRw8PH5VJiYbcZM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XWRw8PH5VJiYbcZM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XWRw8PH5VJiYbcZM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XWRw8PH5VJiYbcZM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster text{fill:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM .cluster span{color:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XWRw8PH5VJiYbcZM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XWRw8PH5VJiYbcZM rect.text{fill:none;stroke-width:0;}#mermaid-svg-XWRw8PH5VJiYbcZM .icon-shape,#mermaid-svg-XWRw8PH5VJiYbcZM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XWRw8PH5VJiYbcZM .icon-shape p,#mermaid-svg-XWRw8PH5VJiYbcZM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XWRw8PH5VJiYbcZM .icon-shape .label rect,#mermaid-svg-XWRw8PH5VJiYbcZM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XWRw8PH5VJiYbcZM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XWRw8PH5VJiYbcZM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XWRw8PH5VJiYbcZM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 请求域名
2. 返回最优边缘节点 IP
3. 请求资源
命中
未命中
用户
智能调度 DNS / GSLB
边缘节点

缓存命中?
直接返回内容
回源站拉取

并写入缓存

1.3 核心架构

  • 源站:存放原始内容,比如网站文件、图片、视频、API 服务。
  • 边缘节点:最靠近用户的缓存节点,负责直接响应用户请求。
  • 区域/中心节点:作为中间层,承接边缘节点回源,减少直接打到源站的流量。
  • 调度系统 / GSLB:全局负载均衡,决定用户请求去哪个节点。
  • 回源系统:边缘节点没有缓存时,从源站或上级节点获取内容。

1.4 缓存机制

CDN 加速效果很大程度上取决于缓存命中率。

关键概念:

  • TTL:缓存有效期。静态资源可以设置较长 TTL,频繁变化的内容设置较短 TTL。
  • Cache-Control / Expires:源站响应头会影响 CDN 缓存行为。
  • 缓存键:通常由域名、路径、查询参数等决定。查询参数过多或不规范会降低命中率。
  • 缓存预热:提前把热门内容推到边缘节点,避免活动开始时集中回源。
  • 缓存刷新:内容更新后,主动清除旧缓存,让用户获取最新版本。

刷新与预热的操作对比:

操作 作用 典型场景
URL 刷新 强制清除指定 URL 的节点缓存,下次访问回源取最新 文件同名覆盖更新
目录刷新 清除整个目录下的缓存 批量发版、整站更新
URL 预热 主动把资源提前拉到边缘节点,不依赖用户首次访问 大促活动、新视频/安装包上线
刷新 + 预热组合 先清旧缓存,再把新内容推到节点 重大活动前的准备

1.5 静态加速 vs 动态加速

  • 静态加速:适合图片、CSS、JS、字体、视频、安装包等。命中缓存后基本不回源。
  • 动态加速:适合 API、登录态、个性化数据等不能长期缓存的内容。主要通过更优路由、协议优化、连接复用来降低延迟。

1.6 路由与协议优化

  • 智能 DNS 调度:根据用户位置、运营商、节点状态选择节点。
  • Anycast / BGP 优化:让用户请求走更优网络路径。
  • HTTP/2、HTTP/3、QUIC:减少连接建立开销,提升弱网体验。
  • TCP 优化:如拥塞控制算法优化,提升长距离传输效率。

1.7 常见应用场景

  • 网站静态资源加速
  • 视频点播 / 直播加速
  • 游戏、APP 安装包分发
  • API 动态加速
  • 跨境电商、出海业务加速
  • DDoS 防护、WAF 安全加速

二、什么情况下可以不上 CDN

2.1 可以不上 CDN 的情况

如果服务同时满足以下条件,不上 CDN 完全没问题:

  • 用户基本都在杭州本地,或者都在同一城市、同一办公楼
  • 访问量不大,服务器带宽和性能扛得住
  • 没有大量图片、视频等大静态资源
  • 不需要防 DDoS、WAF 等安全防护
  • 纯内部系统或小型项目

这种情况下,CDN 带来的加速感知确实不明显,属于"微优化",没必要为了上而上。

2.2 即使都在同一城市,CDN 仍可能有价值

  • 跨运营商问题:杭州用户可能用电信、联通、移动等不同运营商。如果服务器在阿里云(电信机房),移动用户访问时可能要走跨运营商链路,CDN 可以解决这个。
  • 抗并发冲击:即使用户都在本地,如果突然流量暴增(比如促销活动),CDN 能分担源站压力,避免带宽被打满。
  • 隐藏源站 IP:CDN 可以作为一层保护,源站 IP 不直接暴露,提升安全性。
  • 浏览器并发优化:静态资源走 CDN 域名,可以绕过浏览器对同一域名的并发连接数限制(通常 4-6 个),提升页面加载速度。

2.4 决策速查表

你的情况 建议
用户集中本地、流量小、无大静态资源 可以不上
存在明显跨运营商访问问题 建议上
有促销/活动导致流量突增 建议上
有大量图片、视频、安装包分发 强烈建议上
需要防 DDoS、隐藏源站 IP 建议上
静态资源想绕过浏览器单域名并发限制 可以考虑上

三、CDN 多节点缓存不一致问题

3.1 为什么会不一致?

核心原因是:CDN 各边缘节点是独立缓存的,不会自动互相同步。

同一个资源 URL(如 https://cdn.example.com/app.js)可能被北京节点、上海节点、广州节点分别缓存。每个节点缓存的时间点不同,TTL 到期时间也不同。源站更新文件后,如果 URL 没变,就容易出现:

节点状态 返回结果
缓存未过期 返回旧版本
缓存已过期 回源拉取新版本
从未缓存过 直接回源拉取新版本

于是不同用户访问同一个 URL,可能拿到不同版本。
#mermaid-svg-6Uc27GQuUnAU4IGI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6Uc27GQuUnAU4IGI .error-icon{fill:#552222;}#mermaid-svg-6Uc27GQuUnAU4IGI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6Uc27GQuUnAU4IGI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6Uc27GQuUnAU4IGI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6Uc27GQuUnAU4IGI .marker.cross{stroke:#333333;}#mermaid-svg-6Uc27GQuUnAU4IGI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6Uc27GQuUnAU4IGI p{margin:0;}#mermaid-svg-6Uc27GQuUnAU4IGI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster-label text{fill:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster-label span{color:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster-label span p{background-color:transparent;}#mermaid-svg-6Uc27GQuUnAU4IGI .label text,#mermaid-svg-6Uc27GQuUnAU4IGI span{fill:#333;color:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI .node rect,#mermaid-svg-6Uc27GQuUnAU4IGI .node circle,#mermaid-svg-6Uc27GQuUnAU4IGI .node ellipse,#mermaid-svg-6Uc27GQuUnAU4IGI .node polygon,#mermaid-svg-6Uc27GQuUnAU4IGI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6Uc27GQuUnAU4IGI .rough-node .label text,#mermaid-svg-6Uc27GQuUnAU4IGI .node .label text,#mermaid-svg-6Uc27GQuUnAU4IGI .image-shape .label,#mermaid-svg-6Uc27GQuUnAU4IGI .icon-shape .label{text-anchor:middle;}#mermaid-svg-6Uc27GQuUnAU4IGI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6Uc27GQuUnAU4IGI .rough-node .label,#mermaid-svg-6Uc27GQuUnAU4IGI .node .label,#mermaid-svg-6Uc27GQuUnAU4IGI .image-shape .label,#mermaid-svg-6Uc27GQuUnAU4IGI .icon-shape .label{text-align:center;}#mermaid-svg-6Uc27GQuUnAU4IGI .node.clickable{cursor:pointer;}#mermaid-svg-6Uc27GQuUnAU4IGI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6Uc27GQuUnAU4IGI .arrowheadPath{fill:#333333;}#mermaid-svg-6Uc27GQuUnAU4IGI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6Uc27GQuUnAU4IGI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6Uc27GQuUnAU4IGI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6Uc27GQuUnAU4IGI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6Uc27GQuUnAU4IGI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6Uc27GQuUnAU4IGI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster text{fill:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI .cluster span{color:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6Uc27GQuUnAU4IGI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6Uc27GQuUnAU4IGI rect.text{fill:none;stroke-width:0;}#mermaid-svg-6Uc27GQuUnAU4IGI .icon-shape,#mermaid-svg-6Uc27GQuUnAU4IGI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6Uc27GQuUnAU4IGI .icon-shape p,#mermaid-svg-6Uc27GQuUnAU4IGI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6Uc27GQuUnAU4IGI .icon-shape .label rect,#mermaid-svg-6Uc27GQuUnAU4IGI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6Uc27GQuUnAU4IGI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6Uc27GQuUnAU4IGI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6Uc27GQuUnAU4IGI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 返回 v1
回源拿到 v2
直接回源 v2
源站:app.js 已更新为 v2
北京节点

缓存 v1 未过期
上海节点

缓存已过期
广州节点

从未缓存
用户 A 看到 v1
用户 B 看到 v2
用户 C 看到 v2

3.2 常见触发场景

  • 源站用同名文件覆盖旧文件 :比如重新上传了 app.js,但文件名没变。
  • 各节点 TTL 到期时间不同:有的节点刚缓存,有的快过期了。
  • 缓存键配置不当:比如 CDN 配置了"忽略全部参数",但源站会根据参数返回不同内容,不同节点就可能缓存出不同结果。
  • 只刷新了部分节点:比如只刷新了某个目录,但个别 URL 没覆盖到。

3.3 解决方案

  1. 文件名带版本号或哈希

    例如:/app.v1.js、/app.abc123.js

    这样每次发布都是新 URL,CDN 天然不会混用旧缓存。

  2. URL 加版本参数

    例如:/app.js?v=2

    但要注意,如果 CDN 配置了"忽略查询参数",这个参数可能不会生效,需要确认缓存键规则。

  3. 发布后主动刷新缓存

    更新源站后,通过 CDN 控制台或 API 刷新对应 URL、目录或正则路径。如果是同名文件覆盖,建议使用强制刷新,避免节点回源时仍命中 304 而继续使用旧缓存。

  4. 合理设置缓存键

    如果源站会根据参数返回不同内容,就不要简单配置"忽略全部参数"。

  5. 对重要资源设置较短 TTL

    比如 HTML、配置接口、经常变更的静态资源,不要设置太长的缓存时间。

3.4 实际工程中最常用的做法

前端静态资源一般用 文件名哈希 + 长 TTL ;HTML 或配置类资源用 短 TTL 或发布后刷新。这样既能保证加速效果,又能避免多节点缓存不一致。


四、CDN 调度系统

4.1 谁在提供调度服务?

CDN 调度系统通常是由 CDN 厂商自己的调度服务 在提供服务,而不是某个通用公共系统。它在技术上也叫 GSLB / 全局负载均衡,可以理解为 CDN 的"大脑"。

4.2 调度系统具体做什么?

当用户访问一个接入 CDN 的域名时,调度系统主要做这些事:

  1. 接管 DNS 解析:你的域名会 CNAME 到 CDN 厂商提供的调度域名。
  2. 判断用户从哪里来:根据用户 IP 判断城市、运营商、网络类型。
  3. 选择最优节点:综合考虑地理位置、节点负载、链路延迟、丢包率、节点健康状态等。
  4. 返回最近节点 IP:用户拿到 IP 后,直接向这个边缘节点请求内容。
  5. 故障时自动切换:如果某个节点挂了,调度系统会把后续请求切到其他正常节点。

4.3 一句话理解

CDN 调度系统 = CDN 厂商提供的智能 DNS / GSLB 服务。 它负责在用户访问的第一时间,把请求"指路"到最合适的边缘节点;边缘节点则负责真正缓存和返回内容。


五、访问 CDN 的网络链路

5.1 一次完整的 CDN 访问链路

以域名 www.example.com 接入 CDN 为例:

  1. 用户访问域名 :浏览器请求 https://www.example.com/index.html。
  2. 向本地 DNS 发起解析 :浏览器先问本地 DNS:www.example.com 的 IP 是多少?
  3. 域名返回 CNAME 记录 :域名的权威 DNS 发现这个域名已经接入 CDN,于是返回一个 CNAME,例如:www.example.com.c.cdnhwc1.com。
  4. 解析请求进入 CDN 调度系统:本地 DNS 继续解析这个 CNAME,请求会到达 CDN 厂商的智能 DNS / GSLB。
  5. 调度系统选择最优节点:调度系统根据用户位置、运营商、节点健康状态、节点负载、链路延迟等,选出一个最合适的边缘节点 IP。
  6. 返回边缘节点 IP:CDN 调度系统把这个节点 IP 返回给本地 DNS,本地 DNS 再返回给用户浏览器。
  7. 用户向边缘节点发起 HTTP/HTTPS 请求:浏览器拿到 IP 后,直接向这个 CDN 边缘节点请求资源。
  8. 边缘节点判断是否命中缓存 :
    • 命中缓存:边缘节点直接返回资源给用户,速度最快。
    • 未命中缓存:边缘节点回源站拉取资源,缓存后再返回给用户。

完整链路时序图:
源站 边缘节点 CDN 调度系统 权威 DNS 本地 DNS 用户浏览器 源站 边缘节点 CDN 调度系统 权威 DNS 本地 DNS 用户浏览器 #mermaid-svg-CfvWKpLm55EXHZKk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CfvWKpLm55EXHZKk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CfvWKpLm55EXHZKk .error-icon{fill:#552222;}#mermaid-svg-CfvWKpLm55EXHZKk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CfvWKpLm55EXHZKk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CfvWKpLm55EXHZKk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CfvWKpLm55EXHZKk .marker.cross{stroke:#333333;}#mermaid-svg-CfvWKpLm55EXHZKk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CfvWKpLm55EXHZKk p{margin:0;}#mermaid-svg-CfvWKpLm55EXHZKk .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CfvWKpLm55EXHZKk text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-CfvWKpLm55EXHZKk .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CfvWKpLm55EXHZKk .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-CfvWKpLm55EXHZKk .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-CfvWKpLm55EXHZKk .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-CfvWKpLm55EXHZKk #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-CfvWKpLm55EXHZKk .sequenceNumber{fill:white;}#mermaid-svg-CfvWKpLm55EXHZKk #sequencenumber{fill:#333;}#mermaid-svg-CfvWKpLm55EXHZKk #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-CfvWKpLm55EXHZKk .messageText{fill:#333;stroke:none;}#mermaid-svg-CfvWKpLm55EXHZKk .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CfvWKpLm55EXHZKk .labelText,#mermaid-svg-CfvWKpLm55EXHZKk .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-CfvWKpLm55EXHZKk .loopText,#mermaid-svg-CfvWKpLm55EXHZKk .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-CfvWKpLm55EXHZKk .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CfvWKpLm55EXHZKk .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-CfvWKpLm55EXHZKk .noteText,#mermaid-svg-CfvWKpLm55EXHZKk .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-CfvWKpLm55EXHZKk .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CfvWKpLm55EXHZKk .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CfvWKpLm55EXHZKk .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CfvWKpLm55EXHZKk .actorPopupMenu{position:absolute;}#mermaid-svg-CfvWKpLm55EXHZKk .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-CfvWKpLm55EXHZKk .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CfvWKpLm55EXHZKk .actor-man circle,#mermaid-svg-CfvWKpLm55EXHZKk line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-CfvWKpLm55EXHZKk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt 缓存命中 缓存未命中 请求解析 www.example.com 1 递归查询 2 返回 CNAME(CDN 厂商调度域名) 3 继续解析 CNAME 4 按地域/运营商/负载返回最优节点 IP 5 返回边缘节点 IP 6 发起 HTTP/HTTPS 请求 7 直接返回资源(X-Cache: HIT) 8 回源拉取 9 返回内容 10 返回资源并缓存(X-Cache: MISS) 11

5.2 回源链路可能有层级

很多 CDN 不是"边缘节点直接回源站",而是分级缓存:

复制代码
用户 → L1 边缘节点 → L2 区域节点 → 源站

如果 L1 边缘节点没有缓存,可能先去 L2 区域节点找;L2 也没有,再回源站。这样能减少源站压力,也能让同一区域的内容更快分发。
#mermaid-svg-o8zvtmYAkURx77v2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o8zvtmYAkURx77v2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o8zvtmYAkURx77v2 .error-icon{fill:#552222;}#mermaid-svg-o8zvtmYAkURx77v2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o8zvtmYAkURx77v2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o8zvtmYAkURx77v2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o8zvtmYAkURx77v2 .marker.cross{stroke:#333333;}#mermaid-svg-o8zvtmYAkURx77v2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o8zvtmYAkURx77v2 p{margin:0;}#mermaid-svg-o8zvtmYAkURx77v2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o8zvtmYAkURx77v2 .cluster-label text{fill:#333;}#mermaid-svg-o8zvtmYAkURx77v2 .cluster-label span{color:#333;}#mermaid-svg-o8zvtmYAkURx77v2 .cluster-label span p{background-color:transparent;}#mermaid-svg-o8zvtmYAkURx77v2 .label text,#mermaid-svg-o8zvtmYAkURx77v2 span{fill:#333;color:#333;}#mermaid-svg-o8zvtmYAkURx77v2 .node rect,#mermaid-svg-o8zvtmYAkURx77v2 .node circle,#mermaid-svg-o8zvtmYAkURx77v2 .node ellipse,#mermaid-svg-o8zvtmYAkURx77v2 .node polygon,#mermaid-svg-o8zvtmYAkURx77v2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o8zvtmYAkURx77v2 .rough-node .label text,#mermaid-svg-o8zvtmYAkURx77v2 .node .label text,#mermaid-svg-o8zvtmYAkURx77v2 .image-shape .label,#mermaid-svg-o8zvtmYAkURx77v2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-o8zvtmYAkURx77v2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o8zvtmYAkURx77v2 .rough-node .label,#mermaid-svg-o8zvtmYAkURx77v2 .node .label,#mermaid-svg-o8zvtmYAkURx77v2 .image-shape .label,#mermaid-svg-o8zvtmYAkURx77v2 .icon-shape .label{text-align:center;}#mermaid-svg-o8zvtmYAkURx77v2 .node.clickable{cursor:pointer;}#mermaid-svg-o8zvtmYAkURx77v2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o8zvtmYAkURx77v2 .arrowheadPath{fill:#333333;}#mermaid-svg-o8zvtmYAkURx77v2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o8zvtmYAkURx77v2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o8zvtmYAkURx77v2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o8zvtmYAkURx77v2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o8zvtmYAkURx77v2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o8zvtmYAkURx77v2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o8zvtmYAkURx77v2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o8zvtmYAkURx77v2 .cluster text{fill:#333;}#mermaid-svg-o8zvtmYAkURx77v2 .cluster span{color:#333;}#mermaid-svg-o8zvtmYAkURx77v2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o8zvtmYAkURx77v2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o8zvtmYAkURx77v2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-o8zvtmYAkURx77v2 .icon-shape,#mermaid-svg-o8zvtmYAkURx77v2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o8zvtmYAkURx77v2 .icon-shape p,#mermaid-svg-o8zvtmYAkURx77v2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o8zvtmYAkURx77v2 .icon-shape .label rect,#mermaid-svg-o8zvtmYAkURx77v2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o8zvtmYAkURx77v2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o8zvtmYAkURx77v2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o8zvtmYAkURx77v2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 未命中
未命中
内容逐级缓存返回
用户
L1 边缘节点
L2 区域节点
源站

5.3 动态请求链路略有不同

如果是 API、登录态、个性化数据这类动态内容,通常不能长期缓存。CDN 会更多做智能路由和协议优化,把请求更快转发到源站,而不是单纯依赖缓存。

5.4 一句话串起来

用户访问 CDN 时,DNS 先把域名解析成"最近边缘节点 IP",用户再向这个节点请求内容;节点有缓存就直接返回,没有就回源站取。


六、如何判断 CDN 是否生效

6.1 第一步:看 DNS ------ 请求是否走到了 CDN

在终端执行:

bash 复制代码
nslookup www.example.com

或者:

bash 复制代码
dig www.example.com +short

如果返回的 CNAME 包含 cdn、cloudfront、alicdn、qcloud.com 这类 CDN 厂商域名,或者返回多个不同 IP,通常说明请求已经进入了 CDN 调度。

如果始终只返回一个固定 IP,而且这个 IP 就是你源站服务器,那可能还没真正接入 CDN。

6.2 第二步:看响应头 ------ 资源是否命中 CDN 缓存

打开浏览器开发者工具,进入 Network 面板,刷新页面,选中一个静态资源,查看响应头。

重点看这些字段:

字段 含义 说明
X-Cache: HIT 命中 CDN 缓存 资源从 CDN 节点返回,没有回源
X-Cache: MISS 未命中缓存 CDN 节点没有该资源,已回源
Cf-Cache-Status: HIT Cloudflare 命中 仅 Cloudflare 类 CDN 常见
Age 缓存已存在时间 值越大,说明资源在 CDN 节点缓存越久
Via / X-Served-By 经过的代理节点 常能看到 CDN 厂商标识

X-Cache 除了 HIT / MISS,不同厂商还可能出现这些状态:

状态 含义
HIT 命中节点缓存,直接返回
MISS 未命中,已回源拉取
EXPIRED 缓存已过期,回源获取了新内容
STALE 缓存已过期,但仍先用旧内容响应,同时后台异步更新(stale-while-revalidate)
BYPASS / DYNAMIC 该请求不参与缓存,直接转发(常见于动态请求或命中不缓存规则)
UPDATING 该资源正在回源更新中,稍后重试通常会命中

最直观的判断是:

  • X-Cache: HIT:CDN 缓存生效。
  • X-Cache: MISS:CDN 在工作,但这次没命中,已经回源。
  • 完全没有 CDN 相关头:需要确认是否真的接入了 CDN。

也可以用命令行快速检查:

bash 复制代码
curl -I https://www.example.com/static/app.js

6.3 第三步:看 Remote Address ------ 是否连接到 CDN 节点

在 Network 面板里查看资源的 Remote Address。如果它不是你源站 IP,而是 CDN 厂商的节点 IP,说明请求确实走到了 CDN。

但要注意:走到 CDN 不等于一定命中缓存 。比如第一次访问某个资源,CDN 会回源拉取,这时 X-Cache 通常是 MISS。

6.4 分层判断 CDN 是否真正"起作用"

  • 只走到 CDN :DNS 指向 CDN,但 X-Cache: MISS。说明 CDN 已接入,但缓存还没建立。
  • 缓存已生效 :X-Cache: HIT,Age 大于 0。说明资源确实从 CDN 节点返回。
  • 加速效果明显 :同一资源多次请求,第二次明显更快,且状态为 HIT。
  • 未接入 CDN:DNS 仍指向源站 IP,响应头也没有任何 CDN 标识。

6.5 实用排查顺序

  1. 先 nslookup 看域名是否解析到 CDN。
  2. 再打开 Network 面板看资源是否来自 CDN IP。
  3. 然后看 X-Cache 判断是否命中缓存。
  4. 最后看 Age 和加载时间,确认缓存是否稳定生效。

提示 :如果在本地调试,记得关闭开发者工具里的 Disable cache,否则浏览器会绕过本地缓存,影响对 CDN 命中情况的判断。


七、CDN 缓存与浏览器缓存的关系

CDN 缓存不是孤立的一层。一次请求背后通常有三级缓存:浏览器本地缓存 → CDN 边缘缓存 → 源站。理解 HTTP 缓存(强缓存 / 协商缓存),才能搞清"为什么改了代码用户还是看到旧页面"。

7.1 强缓存 vs 协商缓存

对比项 强缓存 协商缓存
相关头字段 Cache-Control: max-age / Expires ETag + If-None-Match;Last-Modified + If-Modified-Since
是否发请求 不发,直接用本地副本 发请求到服务器(CDN/源站)确认
返回结果 200(from memory / disk cache) 未变化返回 304;变化返回 200 + 新内容
优先级 命中则不再走协商缓存 强缓存失效后才走
典型用法 带哈希文件名的静态资源,设长 TTL HTML、配置接口等要求及时更新的资源

7.2 三级缓存判断流程

#mermaid-svg-zosSYKLc3ExyCzI7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zosSYKLc3ExyCzI7 .error-icon{fill:#552222;}#mermaid-svg-zosSYKLc3ExyCzI7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zosSYKLc3ExyCzI7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zosSYKLc3ExyCzI7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zosSYKLc3ExyCzI7 .marker.cross{stroke:#333333;}#mermaid-svg-zosSYKLc3ExyCzI7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zosSYKLc3ExyCzI7 p{margin:0;}#mermaid-svg-zosSYKLc3ExyCzI7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster-label text{fill:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster-label span{color:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster-label span p{background-color:transparent;}#mermaid-svg-zosSYKLc3ExyCzI7 .label text,#mermaid-svg-zosSYKLc3ExyCzI7 span{fill:#333;color:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 .node rect,#mermaid-svg-zosSYKLc3ExyCzI7 .node circle,#mermaid-svg-zosSYKLc3ExyCzI7 .node ellipse,#mermaid-svg-zosSYKLc3ExyCzI7 .node polygon,#mermaid-svg-zosSYKLc3ExyCzI7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zosSYKLc3ExyCzI7 .rough-node .label text,#mermaid-svg-zosSYKLc3ExyCzI7 .node .label text,#mermaid-svg-zosSYKLc3ExyCzI7 .image-shape .label,#mermaid-svg-zosSYKLc3ExyCzI7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-zosSYKLc3ExyCzI7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zosSYKLc3ExyCzI7 .rough-node .label,#mermaid-svg-zosSYKLc3ExyCzI7 .node .label,#mermaid-svg-zosSYKLc3ExyCzI7 .image-shape .label,#mermaid-svg-zosSYKLc3ExyCzI7 .icon-shape .label{text-align:center;}#mermaid-svg-zosSYKLc3ExyCzI7 .node.clickable{cursor:pointer;}#mermaid-svg-zosSYKLc3ExyCzI7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zosSYKLc3ExyCzI7 .arrowheadPath{fill:#333333;}#mermaid-svg-zosSYKLc3ExyCzI7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zosSYKLc3ExyCzI7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zosSYKLc3ExyCzI7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zosSYKLc3ExyCzI7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zosSYKLc3ExyCzI7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zosSYKLc3ExyCzI7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster text{fill:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 .cluster span{color:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zosSYKLc3ExyCzI7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zosSYKLc3ExyCzI7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-zosSYKLc3ExyCzI7 .icon-shape,#mermaid-svg-zosSYKLc3ExyCzI7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zosSYKLc3ExyCzI7 .icon-shape p,#mermaid-svg-zosSYKLc3ExyCzI7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zosSYKLc3ExyCzI7 .icon-shape .label rect,#mermaid-svg-zosSYKLc3ExyCzI7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zosSYKLc3ExyCzI7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zosSYKLc3ExyCzI7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zosSYKLc3ExyCzI7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否 / 过期
没变
变了
浏览器发起请求
浏览器本地缓存

仍在有效期内?
直接使用本地缓存

不发网络请求
CDN 边缘节点

缓存有效?
CDN 返回 200

X-Cache: HIT
CDN 回源

携带 If-None-Match 等协商头
源站内容

变化了吗?
源站返回 304

各级缓存继续用旧内容
源站返回 200 + 新内容

CDN、浏览器逐级更新缓存

7.3 关键结论

  • HTML 通常不能用长强缓存 :要保证用户拿到最新入口,HTML 一般用 Cache-Control: no-cache(每次协商)或短 TTL。
  • 带哈希的静态资源放心长缓存:文件内容变 → 文件名变 → URL 变,天然绕开旧缓存。
  • CDN 缓存与浏览器缓存相互独立:浏览器缓存过期不代表 CDN 缓存过期,排查"更新不生效"时两层都要看。

八、防盗链与 URL 鉴权

CDN 按流量/带宽计费,资源被外站盗用会直接烧钱,所以防盗链是 CDN 的必备能力。

8.1 常见防护方式对比

方式 原理 优点 局限
Referer 防盗链 校验请求头 Referer,配置白/黑名单 配置简单,控制台即可开启 Referer 可伪造;需考虑空 Referer 的处理
URL 鉴权(时间戳+签名) URL 附带签名和过期时间,节点校验通过才返回 安全性高,链接有时效 需要服务端生成签名 URL
IP 黑白名单 按来源 IP 放行或拦截 简单直接 公网用户 IP 不固定,更适合封禁场景
UA 防盗链 校验 User-Agent,拦截爬虫/下载工具 能挡住常见恶意 UA UA 容易伪造
HLS 加密 / DRM 视频内容加密 + 授权播放 防盗效果最强 实现复杂,有额外成本

8.2 URL 鉴权的签名思路

text 复制代码
原始 URL: https://cdn.example.com/video.mp4
签名 URL: https://cdn.example.com/video.mp4?auth_key=时间戳-rand-uid-md5哈希
校验逻辑: 节点用相同密钥重算哈希,比对一致且未过期才返回内容

要点:签名 URL 自带过期时间,防盗效果远好于 Referer;视频、下载类资源建议必配。


九、回源细节与常见坑

9.1 回源 HOST

CDN 节点回源时,请求头里的 Host 不一定等于加速域名。

  • 默认回源 Host = 加速域名。
  • 如果源站是 Nginx 虚拟主机 / 网关按 Host 分流,回源 Host 配错会 404 或打到默认站点。

9.2 回源协议

  • HTTP 回源:性能好,但内容明文传输。
  • HTTPS 回源:安全,但源站要承担 TLS 计算压力。
  • 协议跟随:用户用什么协议访问,节点就用什么协议回源,最常用。

9.3 Range 回源(分片缓存)

视频、安装包等大文件,CDN 会按 HTTP Range 分片拉取和缓存:

  • 用户拖动进度条时,只拉取对应分片,不用下载整个文件。
  • 源站需支持 Range 请求,否则大文件回源效率极差。

9.4 获取用户真实 IP

经过 CDN 后,源站看到的连接 IP 是节点 IP,真实用户 IP 在透传头里:

  • X-Forwarded-For:客户端与中间代理 IP 列表,第一个通常是真实用户 IP。
  • X-Real-IP:部分厂商提供的单值真实 IP 头。

安全提示:X-Forwarded-For 可被伪造,服务端应只信任 CDN 节点追加的部分,或使用厂商的可信头(如 Cloudflare 的 CF-Connecting-IP)。


十、命中率、监控与计费

10.1 命中率怎么算

  • 请求命中率 = 命中缓存的请求数 / 总请求数
  • 字节命中率 = 命中缓存返回的字节数 / 总返回字节数

字节命中率更能反映带宽成本的节省:大文件(视频、安装包)只要命中,省的都是实打实的带宽。

10.2 关键监控指标

指标 关注点
命中率 / 回源率 命中率低说明缓存规则或缓存键有问题
带宽 / 流量 判断费用、发现异常刷量
状态码分布 5xx 突增往往意味着源站故障被放大
回源带宽 回源打满源站带宽,会导致源站自身不可用
首字节时间(TTFB) 反映节点响应与回源链路质量

10.3 常见计费方式

计费方式 说明 适合场景
按流量 每 GB 计费,单价稍高 流量平稳的中小站点
按带宽峰值 按当日带宽峰值(Mbps)计费 流量集中在高峰突增的场景
月度 95 峰值带宽 去掉当月最高 5% 的峰值后计费 大流量、波动大的业务
按请求数 部分厂商对 HTTPS 请求数额外收费 HTTPS 高并发场景

十一、接入 CDN 的标准流程

#mermaid-svg-faARyKM9JfCgvEZd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-faARyKM9JfCgvEZd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-faARyKM9JfCgvEZd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-faARyKM9JfCgvEZd .error-icon{fill:#552222;}#mermaid-svg-faARyKM9JfCgvEZd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-faARyKM9JfCgvEZd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-faARyKM9JfCgvEZd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-faARyKM9JfCgvEZd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-faARyKM9JfCgvEZd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-faARyKM9JfCgvEZd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-faARyKM9JfCgvEZd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-faARyKM9JfCgvEZd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-faARyKM9JfCgvEZd .marker.cross{stroke:#333333;}#mermaid-svg-faARyKM9JfCgvEZd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-faARyKM9JfCgvEZd p{margin:0;}#mermaid-svg-faARyKM9JfCgvEZd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-faARyKM9JfCgvEZd .cluster-label text{fill:#333;}#mermaid-svg-faARyKM9JfCgvEZd .cluster-label span{color:#333;}#mermaid-svg-faARyKM9JfCgvEZd .cluster-label span p{background-color:transparent;}#mermaid-svg-faARyKM9JfCgvEZd .label text,#mermaid-svg-faARyKM9JfCgvEZd span{fill:#333;color:#333;}#mermaid-svg-faARyKM9JfCgvEZd .node rect,#mermaid-svg-faARyKM9JfCgvEZd .node circle,#mermaid-svg-faARyKM9JfCgvEZd .node ellipse,#mermaid-svg-faARyKM9JfCgvEZd .node polygon,#mermaid-svg-faARyKM9JfCgvEZd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-faARyKM9JfCgvEZd .rough-node .label text,#mermaid-svg-faARyKM9JfCgvEZd .node .label text,#mermaid-svg-faARyKM9JfCgvEZd .image-shape .label,#mermaid-svg-faARyKM9JfCgvEZd .icon-shape .label{text-anchor:middle;}#mermaid-svg-faARyKM9JfCgvEZd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-faARyKM9JfCgvEZd .rough-node .label,#mermaid-svg-faARyKM9JfCgvEZd .node .label,#mermaid-svg-faARyKM9JfCgvEZd .image-shape .label,#mermaid-svg-faARyKM9JfCgvEZd .icon-shape .label{text-align:center;}#mermaid-svg-faARyKM9JfCgvEZd .node.clickable{cursor:pointer;}#mermaid-svg-faARyKM9JfCgvEZd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-faARyKM9JfCgvEZd .arrowheadPath{fill:#333333;}#mermaid-svg-faARyKM9JfCgvEZd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-faARyKM9JfCgvEZd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-faARyKM9JfCgvEZd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-faARyKM9JfCgvEZd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-faARyKM9JfCgvEZd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-faARyKM9JfCgvEZd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-faARyKM9JfCgvEZd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-faARyKM9JfCgvEZd .cluster text{fill:#333;}#mermaid-svg-faARyKM9JfCgvEZd .cluster span{color:#333;}#mermaid-svg-faARyKM9JfCgvEZd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-faARyKM9JfCgvEZd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-faARyKM9JfCgvEZd rect.text{fill:none;stroke-width:0;}#mermaid-svg-faARyKM9JfCgvEZd .icon-shape,#mermaid-svg-faARyKM9JfCgvEZd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-faARyKM9JfCgvEZd .icon-shape p,#mermaid-svg-faARyKM9JfCgvEZd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-faARyKM9JfCgvEZd .icon-shape .label rect,#mermaid-svg-faARyKM9JfCgvEZd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-faARyKM9JfCgvEZd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-faARyKM9JfCgvEZd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-faARyKM9JfCgvEZd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 添加加速域名
2. 配置源站

IP 或源站域名
3. 配置缓存规则

TTL / 缓存键 / 防盗链
4. 获取 CNAME 记录
5. 到 DNS 服务商

添加 CNAME 解析
6. 验证生效

nslookup + X-Cache

验证要点:

  • nslookup / dig 确认域名已 CNAME 到厂商调度域名。
  • 请求静态资源,确认响应头出现 X-Cache: HIT。
  • 观察监控面板的命中率是否逐步上升。

十二、常见问题排查(FAQ)

现象 常见原因 处理方式
缓存命中率低 URL 带随机参数、TTL 太短、缓存键配置不当 统一/忽略无关参数、调长 TTL、规范缓存键
更新后用户仍看到旧内容 各节点旧缓存未失效、浏览器强缓存未过期 文件名带哈希 + 发布后刷新;HTML 用协商缓存
接入 CDN 后源站 404 回源 Host 配置错误 检查回源 Host 与源站虚拟主机配置
刷新后仍是旧内容 刷新任务未生效、浏览器本地缓存 刷新一般几分钟内生效,浏览器强刷(Ctrl+F5)
跨域请求报 CORS 错误 CDN 未透传 Access-Control-Allow-Origin 等头 源站正确配置 CORS;多来源时加 Vary: Origin,避免缓存串响应头
源站看到的全是节点 IP 未解析透传头 从 X-Forwarded-For 等可信头取真实 IP
账单突增 资源被盗刷、热门大文件被外站盗链 配置防盗链 / URL 鉴权,设置用量封顶与告警
相关推荐
为思念酝酿的痛2 小时前
NAT技术--网络地址转换原理
网络·计算机网络·智能路由器
该逃避避2 小时前
出海广告跑不起来怎么办?动态住宅IP助力广告跑量
运维·服务器·网络
一条泥憨鱼2 小时前
【从0开始学习计算机网络】| ip协议-ttl-标识-分片偏移-ip分片与重组
运维·服务器·网络
不像程序员的程序媛11 小时前
检测网络的命令mtr详解
网络
天启HTTP12 小时前
爬虫防封核心原理:IP轮换机制与风控规避逻辑
linux·服务器·网络·爬虫·tcp/ip
运维行者_12 小时前
网络性能监控怎么做?从自动发现到根因分析的4个环节
运维·服务器·网络·人工智能·支持向量机
hz5678914 小时前
涉密视频会议设备配置指南:终端、音视频采集与配套设施选型
服务器·网络·数据库·安全·实时音视频·信息与通信·智能硬件
优橙教育14 小时前
零基础学AI应用开发要多久?3个月能到什么水平
服务器·开发语言·网络·php
AIgorithmGEEK15 小时前
[Linux]从手写报头到内核套路:序列化、反序列化与自定义协议全链路
linux·运维·服务器·网络·序列化·反序列化