网站打开慢、视频转圈、活动页面一上线就卡死——这几个问题几乎每个做网站和业务系统的人都碰到过。我第一次被逼着系统研究CDN,就是因为一个活动页在刚开始的两分钟内直接被打满,源站CPU跑到99%,用户反馈全是加载失败。那时候我才意识到,光靠加带宽、加机器根本治不了本,真正该解决的是"内容离用户太远"这个结构性问题。
CDN,全称Content Delivery Network,内容分发网络,云计算基础课程里第七章的重头戏。它做的事情听起来很简单:把源站的内容复制到离用户更近的节点上,让用户就近获取数据。但真把它用好、配明白,里面的门道比大多数人想象的多得多。这篇文章我不打算复述教科书,而是结合我这几年的实际使用经验,把CDN的前因后果、核心机制、配置细节和排查方法一次讲透。不管是正在学云计算基础的学生,还是刚接手网站运维的朋友,都应该能从这里拿到可以直接用的东西。
1. CDN整体认知与核心思路拆解
1.1 CDN到底是什么:从一次普通的网页访问说起
先从一个最普通的场景出发。假如你的网站源站部署在某东部城市的数据中心,用户在西部省份打开你的页面。没有CDN时,这个用户的请求要跨越几千公里的物理距离,经过骨干网、城域网、最后一公里接入,才能到达你的服务器并返回内容。如果赶上晚高峰,跨网跨地区丢包严重,页面加载十几秒是常有的事。
加了一台CDN节点在西部省份之后,情况就变了。用户请求先打到当地或邻近省份的CDN边缘节点,这个节点如果缓存着你网站的静态资源,就直接把内容返回给用户。整个过程可能只经过几十到一百多公里的距离,延迟从几十毫秒降到几毫秒。用户感知最强烈的是首屏速度明显提升,图片、脚本、样式表基本都是瞬时加载。
但CDN绝不只是一个"大缓存"。它是一个由调度系统、边缘节点、中间层节点、源站共同组成的完整分发体系。用户根本不需要直接连源站,而是通过CDN服务商提供的专用域名(CNAME)接入调度系统,由调度系统动态决定给用户分配哪一个边缘节点的IP。
我习惯用一个生活类比来解释这个逻辑:没有CDN时,全城的人都只能去市中心唯一的一家大超市买东西,路途远、结账排队。有了CDN,相当于在每个小区门口都开了便利店,常用商品提前从总仓运到便利店库存。你出门走两步就能买到东西了,总仓那边也不会因为万人涌入而瘫痪。便利店里没有的稀有商品,便利店再去总仓调货——这个过程就叫回源。
1.2 没有CDN时,网站到底在承受什么
很多人会有疑问:我服务器配置又不低,带宽也买了,为什么不能直接扛住所有请求?这个问题的本质在于:单一源站在物理上就撑不住大范围的流量分布。
首先是跨网跨地域延迟。国内三大运营商的互联互通问题虽然这些年缓解了不少,但跨网访问的延迟和丢包依然客观存在。用户在北京访问一个南方机房的网站,光物理距离就决定了延迟下限。哪怕你网络优化做得再好,这个物理约束也绕不开。
其次是高峰期的并发压力。做电商的都懂,大促期间的流量曲线和平日完全不同,瞬时QPS可能是平时的几十倍。如果你买带宽是按照峰值去买的,平时就是巨大的浪费;你不按峰值买,高峰期又必然扛不住。CDN把大部分请求拦截在边缘节点,源站只需要处理边缘节点未命中而回源的请求,流量压力至少下降一个数量级。
第三是单点故障风险。源站机房如果出现问题,比如机房断电、光缆被挖断、服务器宕机,那所有用户就全都访问不了。而CDN边缘节点宕机时,调度系统会自动把流量切换到其他可用节点,对用户来说基本无感。源站故障时,CDN节点上已有的缓存内容还能继续为老用户服务,相当于多了一层保险。
所以我现在做技术方案时,CDN已经不是一个可选项,而是所有对外服务的标配前置层。它同时解决了性能、成本和可用性三个问题。
1.3 CDN的整体架构:四层模型一次看懂
从整体架构看,CDN系统可以拆成四个层次,理解了这四个层次,后面的配置和排查都会有清晰的方向。
第一层是客户端和接入层,也就是用户发起请求后,第一步会访问CDN服务商提供的调度系统域名。这个域名通常以CNAME的形式存在,比如你的网站是example.com,CDN加速域名可能就是example.com.cdn.com这样的形式。
第二层是调度层,也就是全局负载均衡(GSLB)。它负责接收用户的DNS解析请求,根据用户的IP地理位置、所属运营商、节点实时负载等因素,返回一个"最优"的边缘节点IP。这个过程发生在用户的浏览器或客户端发起HTTP请求之前,用户态完全无感。
第三层是边缘节点层。它们是真正离用户最近的服务器,负责处理用户请求、提供缓存内容、执行缓存策略,以及在未命中时向上查询或直接回源拉取数据。边缘节点覆盖在全国以及全球各主要城市和运营商网络内。
第四层是源站层。源站是内容真正的所在地,所有的原始数据都存储在这里。边缘节点缓存的内容、中间层节点缓存的内容,最终都是从源站获取的。源站可以是一台服务器,也可以是一个负载均衡集群,甚至可以是一个对象存储桶。
在实际部署中,大型CDN还会在边缘节点和源站之间设置一个中间层,用于合并回源请求。举个例子,同一时刻有100个边缘节点都在请求同一个热点资源,如果没有中间层,源站会被这100个请求打爆。有了中间层,100个请求会在中间层汇聚,如果中间层已经缓存了这个资源,它直接返回;如果没有,中间层只向源站发起一个请求,再把结果分发给100个边缘节点。这个设计极大降低了源站的回源压力。
2. 核心机制细节解析与实操要点
2.1 全局负载均衡:CDN怎么知道把用户送哪个节点
CDN调度并不像很多人想象的那样"随机分配"或者"简单就近"。它的核心技术叫全局负载均衡(GSLB),常见实现方式是基于DNS的调度。
我举一个具体的流程例子。用户输入www.example.com,浏览器发起DNS查询时,本地DNS服务器会发现这个域名有一条CNAME记录,指向CDN服务商提供的调度域名,比如www.example.com.cdn.cnames.net。于是DNS查询被引导到了CDN服务商的权威DNS服务器上。这时候,调度系统会根据查询请求中包含的解析者IP(也就是用户所在网络出口的IP),做以下判断:
第一是地理位置。系统会把IP映射到地理区域,通常精确到省级层面,挑选离用户最近的节点。比如用户在广东,就优先分配广东的节点;广东没有节点或过载,就分配华南区域的节点。
第二是运营商归属。IP也在一定程度上反映了用户所属的运营商,系统会优先分配与用户同运营商的节点,减少跨网访问。同一地区的联通用户和电信用户,很可能会被分配到不同的节点IP。
第三是节点实时负载。即使某个节点离用户很近,但如果当前负载过高、带宽接近打满,调度系统也会尝试把部分流量安排到其他负载较低但稍远一些的节点。这就是"基于负载的动态调度"。
有一个细节需要注意:基于DNS的调度实际上是依赖递归DNS和权威DNS之间传递的"解析者IP"来做判断的。如果用户用的是公共DNS,这个IP是公共DNS的出口IP,而不是用户真实的上网IP,调度精度可能不准。所以一些平台级应用会使用HTTPDNS方案,也就是在客户端直接发HTTP请求到调度服务,带着客户端自己的真实IP做调度,精度更高、响应更快。这个点是很多教科书不讲、但在实际移动端开发中非常关键的技术。
2.2 缓存机制:缓什么、怎么缓、什么时候失效
CDN的核心就是缓存,但缓存的细节特别容易出错。首先要理解"缓存键"的概念。CDN判断一个请求是否命中缓存,靠的是缓存键,默认情况下就是完整的URL。同一个URL的请求可以复用缓存内容;URL不同,哪怕是同一个文件带有不同参数,也通常算作不同的缓存项。
接下来是缓存位置的层级。边缘节点会先在内存或本地磁盘中查找缓存;未命中时,会尝试向中间层节点发起请求,看中间层是否有缓存;仍然未命中时,才会回源取数据。这个"边缘节点—中间层—源站"的层次结构,决定了回源率高低和请求延迟。
缓存的过期策略主要看两类信息。一类是HTTP协议自带的缓存控制头,比如Cache-Control和Expires,这是标准做法,也是我建议首要设置的;另一类是CDN服务商自己在控制台上配置的缓存规则,比如针对某个路径、某种文件类型设置固定的缓存时长。这两类信息在实际运行时是协同工作的:通常遵循"显式配置优先于协议默认值"的原则,但具体到不同服务商可能略有差异,我的建议是全部显式配置,不给默认值留机会。
缓存淘汰上,边缘节点内存有限,不可能无限缓存所有内容。普遍使用的是LRU(Least Recently Used)策略:当缓存空间不足时,优先淘汰最近最少被访问的内容。所以并不是你设置了缓存时长,内容就一定会一直留在节点上;如果这个节点的缓存容量本来就小、访问量又大,即使没过期,内容也可能因为被淘汰而需要重新回源。这一层逻辑解释了为什么有时候你明明设置了很长的缓存时间,回源率却依然不低。
2.3 回源与缓存更新:刷新和预热的区别你搞清楚了吗
回源是CDN架构里最绕不开的动作。用户请求到达边缘节点后,节点发现没有缓存或缓存已过期,就需要向上游节点或源站发起请求,把内容拉回来,然后再返回给用户。
回源有两个核心指标:回源率和回源流量。回源率等于回源请求数占全部请求数的比例,这个数字当然是越低越好。回源率越低,说明CDN缓存的命中率越高,用户感受到的延迟就越低,源站的压力也越小。我在实际项目中会把回源率作为CDN健康度的第一观察指标。正常情况下,静态资源的回源率应该控制在10%以下,热门资源甚至可以做到2%以下。
缓存更新的问题就来了:源站内容更新了,CDN节点上的旧缓存怎么办?这里要分清两个概念:刷新和预热。
刷新就是主动删除CDN节点上的缓存。执行刷新操作后,该资源在CDN上的缓存会立即失效,用户下次请求会重新回源拿到最新内容。刷新有URL刷新和目录刷新两种粒度,URL刷新精确到单个文件,目录刷新会让该目录下的所有缓存全部失效。刷新操作需要谨慎使用,尤其是目录刷新,一旦执行,该目录下所有文件都会触发回源,可能瞬间给源站带来较大的压力。
预热则是在内容更新后,主动让CDN节点提前从源站拉取内容,而不是等用户请求时才回源。预热的典型场景是活动页面上线:活动页面的图片、脚本都是新资源,如果等到用户访问时才逐层回源,第一批用户会感受到明显延迟。我在上线前半小时执行预热操作,让全国主要节点提前把资源拉取到位,用户访问时会直接从缓存中命中,首屏体验会明显更好。
刷新和预热的根本区别在于:刷新是"让缓存失效",预热是"让缓存预先生效"。两个操作在控制台都有入口,但实际使用频率差别很大。日常更新用刷新,发布关键活动用预热,这个经验很实用。
3. 关键技术细节与配置避坑指南
3.1 HTTP缓存头配置:Cache-Control才是你真正要写的
很多人在源站配置缓存策略时,只会在CDN控制台写几个缓存规则,但源站响应里的HTTP缓存头其实更基础、更规范。源站返回内容时带的Cache-Control头,CDN节点会直接参考并执行。
如果源站没有返回Cache-Control,CDN可能会采用控制台上配置的默认缓存规则。但如果源站返回了,情况就复杂起来。我见过太多这样的案例:源站程序员图省事,对所有请求都返回Cache-Control: no-cache,结果CDN上配了再长的缓存时长也失效,所有请求都直接穿透到源站。折腾了一整天的性能优化,最后发现是响应头把CDN的功能废掉了。
那正确的配置方法是什么?我一般按资源类型来分。静态资源(图片、CSS、JS、字体文件):Cache-Control: max-age=31536000,也就是缓存一年。这些文件内容经过版本号控制,更新时URL会发生变化,所以长的缓存时间毫无风险。HTML页面:Cache-Control: max-age=60,缓存一分钟。HTML通常是入口文件,不能缓存太久,但又不能完全不缓存,一分钟是一个比较稳妥的折中。API接口(非敏感公开数据):Cache-Control: max-age=30到300秒,视数据更新频率而定,可以显著降低后端压力。
还要注意区分no-cache和no-store。no-cache的意思是"可以缓存,但每次使用前必须回源验证";no-store的意思是"绝对不能缓存"。
在实际抓包验证时,我会重点关注两个响应头:Age和X-Cache。Age表示缓存内容在CDN节点上存活了多久,X-Cache项常见的值是HIT或MISS,非常直观地告诉你命没命中。用curl -I就能看到这些头,具体命令我在后面排查章节会展示。
3.2 HTTPS加速配置:证书部署和回源证书
现在全网基本都是HTTPS了,CDN上配置HTTPS也属于基本功,但这里面有几个坑值得单独拎出来说。
第一是证书部署的位置。启用CDN加速后,用户访问的是CDN节点,而不再是源站。所以你在源站上部署的证书,在用户和CDN节点这一段是不起作用的。真正起作用的是CDN节点上部署的证书。这要求在CDN控制台配置证书,或者开启CDN服务商提供的免费证书服务。如果不配置,用户访问时会出现证书无效的安全警告,页面直接进不去。
第二是回源证书和回源方式的设置。用户到CDN节点这段是HTTPS,那CDN节点到源站这段呢?默认情况下,很多配置是HTTP回源,也就是CDN节点与源站之间的数据是明文传输的,存在被中间人窃取的风险。一个完整的HTTPS链路,应该做到"全链路HTTPS":用户到CDN节点是HTTPS,CDN回源到源站也是HTTPS。在CDN控制台里找到"回源设置"选项,把回源协议改为HTTPS即可。这需要源站本身已经部署了有效的SSL证书。
第三是证书自动续期。免费证书有效期通常只有90天,每三个月就要手动更新一次,非常容易忘记。我吃过这个亏:某项目忘记续期证书,结果用户访问时提示证书过期,页面被浏览器拦截,业务直接停摆。后来我在控制台里开启了证书自动续期,并且设置了到期前的邮件告警提醒,双保险才算安心。
第四是强制HTTPS跳转。配置CDN后,建议开启HTTP强制跳转HTTPS的规则,避免用户通过HTTP访问时浏览器产生多次重定向,影响加载速度。这个选项在大多数CDN控制台里是一个开关,勾上即可。
3.3 防盗链与URL鉴权:别让你的流量被人白嫖
CDN带宽是按照实际流量计费的,如果有其他网站直接外链你的图片、视频,把你的CDN当图床用,每月的账单会非常难看。这就是必须做防盗链的原因。
最基础的防盗链是基于Referer的判断。CDN节点会检查HTTP请求中的Referer字段,如果来源域名不在允许列表内,就拒绝返回内容或返回错误码。但这种方式的缺点也很明显:Referer字段本身可以被伪造,空Referer(比如直接在浏览器地址栏输入图片URL访问)也常常会被防盗链策略拦截。针对空Referer的处理,可以单独设定是放行还是拒绝。
更可靠的是URL鉴权方式。核心原理是:源站在生成资源链接时,给URL加上签名参数和时间戳。签名通常是对"路径+过期时间+密钥"做MD5或HMAC计算得到的。CDN节点收到请求时,先校验时间戳是否过期,再用相同的密钥和算法重新计算签名,对不上就拒绝访问。这种方式安全性高,应用也广,特别适合视频、游戏资源、软件安装包这类需要防爬防盗的下载场景。
配置URL鉴权时,有一个时间戳校验的细节:过期时间不要设得太长(比如一天),否则获取链接的用户在这段时间内可以无限次访问同一个URL,依然存在被分享扩散的风险。但也不宜设得太短,否则对于需要跨越多步跳转的复杂流程,可能在下载还没开始时链接就过期了。一般我会根据业务请求链路的长度和用户操作时长,把有效期设在可接受范围的中值。
另一个实用技巧是URL重写。CDN本身还提供了URL重写能力,可以把复杂路径映射到缓存路径上。比如用户访问 /api/image?id=123 这个动态接口,你可以在CDN层面把它重写为 /cache/images/123.jpg,让CDN按静态文件去缓存,大幅减轻源站压力。这个技巧在架构改造中经常用到,但它只适用于接口响应可以被安全缓存的场景,改造前务必评估业务语义。
3.4 动静态分离与动态加速
CDN的经典能力是静态加速,但今天很多主流的CDN也提供了动态内容加速能力。所谓动态加速,不是缓存动态内容,而是通过优化回源链路,让CDN节点走更优的网络路径回源,减少公网传输的抖动和丢包。
比如某个接口不能缓存,每次请求都要回源获取实时数据。如果没有CDN,用户直接走公网连源站,路径完全由路由决定,慢或丢包只能认。有了CDN的动态加速,用户先到达最近的CDN节点,这个节点再通过CDN服务商内部的专线或者优化后的公网路由回源,整体链路质量会显著提升。
动静态分离的架构在配置层面也很常见:把静态资源域名(img.example.com、static.example.com)指向CDN加速,动态接口域名(api.example.com)保留直连源站或单独配置动态加速。我在搭建企业官网时通常采用这个方案,静态域名走CDN长缓存策略,API域名走直连或动态加速,两类资源互不干扰,排查问题时也更有针对性。
做动静态分离还有一个附带好处:源站的负载更低,安全防护能力更强。CDN只需要在前面档住静态流量,源站侧的WAF和防火墙压力会小很多。如果所有流量都从一条域名过,那配置的复杂度、安全策略的颗粒度,都会让你头疼不少。
4. 实操过程与核心环节实现
4.1 接入CDN前,这些准备工作必须到位
接入CDN不是进了控制台点点鼠标就行,前面的准备工作越充足,后面踩坑越少。
第一步是梳理源站信息。你要准备好源站的访问地址,它可能是一个域名、一个IP,也可能是一个对象存储的Endpoint。CDN控制台添加加速域名时,会要求填写源站类型和源站地址,这个信息必须准确,否则后面所有回源都会失败。我用过的一个项目就曾因为源站填写了内网IP,结果CDN节点根本访问不到,排查了很久才发现根源。
第二步是确定加速域名。建议不要把主域名直接作为加速域名,而是拆一个子域名,比如static.example.com作为静态资源加速域名。这样即使后面调整CDN配置、切换服务商,对主域名的影响也最小。另一个好处是,你可以针对这个子域名做更精细的缓存策略和频道级别的ChatOps告警。
第三步是准备DNS账号权限。接入CDN后,你需要到域名DNS管理后台解析一条CNAME记录。如果你没有域名解析权限,这一步基本做不了。很多企业内部流程是:CDN配置由运维负责,但DNS在域名管理员那边,两边要先协调好权限和审批路径。否则配置到CNAME这一步时会卡壳。
第四步也是很多人忽略的一步:先估算一下流量规模和峰值带宽,确定CDN服务的计费模式。CDN计费常见模式是按流量计费和按带宽峰值计费。流量较小的官网、活动页适合按流量计费;流量曲线平稳且带宽消耗较高的视频网站则更适合按带宽计费。计价模式选错了,月底账单会有比较明显的差异。
4.2 控制台配置全流程:从添加域名到CNAME生效
准备工作做完,就可以正式进入配置流程了。这里我以通用的操作流程来呈现,不同CDN服务商的控制台大同小异。
第一步:在CDN控制台选择"域名管理",点击"添加加速域名"。填写加速域名,选择业务类型(网页加速、下载加速、视频点播加速等),不同类型对应不同的默认优化策略,初期选择匹配业务形态的类型即可。
第二步:配置源站。填写源站地址和端口。这里要特别注意:CDN回源时走的是HTTP还是HTTPS,取决于你之前的HTTPS回源设置。如果选择HTTPS回源,源站必须能用HTTPS提供服务。
第三步:配置缓存规则。不要只依赖默认配置,要主动添加至少一条针对常见静态资源类型的缓存规则。比如对.jpg、.png、.css、.js后缀的文件设置30天缓存。对于HTML页面,可以单独设置短缓存或不缓存。
第四步:等待CDN分配CNAME地址。添加完成后,控制台会生成一个以CDN服务商域名结尾的CNAME地址,类似 accelerate.example.com.cdnprovider.com。这个地址就是你的加速域名需要解析到的地方。
第五步:到DNS服务商控制台,为加速域名添加一条CNAME记录,记录值填CDN控制台生成的CNAME地址。修改完成后,DNS生效需要几分钟到几小时不等,取决于TTL设置。TTL设得长的话,这个生效时间会明显变长,建议提前修改DNS记录的TTL。
第六步:验证配置是否生效。命令行执行dig加速域名,如果解析结果返回的是CDN服务商分配的节点IP,而不再是你原来源站的IP,说明CNAME解析已经生效。再用nslookup查询一下,确认当前解析到的IP在你预期所在的城市或区域范围内,调度基本就正常了。
4.3 缓存规则与刷新预热实操示例
缓存规则的配置是最能体现工程师对业务理解程度的地方。我给一个通用且好用的示例,直接可抄作业:
- 全局默认规则:缓存30天,优先级较低
- .html、.htm结尾的页面:缓存60秒,因为HTML是入口,更新频率较高
- /admin/路径下的所有文件:不缓存,管理员后台内容必须实时生效
- .jpg、.png、.webp、.css、.js、.woff2等静态资源:缓存365天
- /api/路径下的公开数据接口:缓存60秒到300秒,具体看数据时效性
配置这条规则后,CDN节点会按照URL匹配规则来执行。需要注意的是,规则从上到下按优先级依次匹配,命中即停止。这意味着优先级最高的规则应该放在最上面,比如"/admin/不缓存"这条必须放在"静态资源长缓存"前面,否则管理后台的.js和.css文件也会被长缓存策略覆盖,导致后台样式错乱。
刷新操作在发布新版本当天几乎必做:比如前端上线了新的改版页面,HTML变更了,但CDN上还是旧缓存,那就需要在控制台URL刷新处填入对应的页面地址,点击刷新。如果发布涉及整个目录改动,可以用目录刷新,但要注意它的影响面是做全套目录的缓存失效,慎用。
预热操作适合在活动上线前半小时执行。先把预热的资源URL列表准备好,在控制台"预热"功能中提交。大型活动中,文件量往往较大,我一般会把需要预热的资源列表整理成文本文件,通过控制台上传方式批量提交,比一个个手工填URL高效太多。
配置完成后,别忘了到"监控报表"里看一眼数据。重点关注命中率、回源带宽、回源QPS这几个指标,以及错误状态码分布。如果命中率明显偏低,说明缓存规则配置可能有问题;如果回源带宽突然飙升,说明可能有大量未命中请求打到了源站;如果返回了大量500或502状态码,大概率是源站扛不住了或者回源链路异常。
4.4 日常监控与日志分析
CDN的监控报表通常涵盖带宽、流量、命中率、状态码、回源统计等维度。但我实际操作中,监控报表只是一个概览,真正发现问题更多依赖日志。
开启CDN日志之后,CDN节点会把每个访问请求按照标准格式记录下来,包括请求时间、客户端IP、访问URL、请求方法、状态码、响应字节数、Referer、User-Agent等字段。日志生成后一般会打包投递到对象存储中,方便用脚本做离线分析。
我会用一行简单命令从日志里提取回源比例较高的URL:
grep '"miss"' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20日志格式不同,字段位置和标识不一样,但核心思路就是:筛选出缓存未命中的请求,按URL聚合统计,排名靠前的就是回源最集中的资源,也就是你需要优化缓存策略或做预热的重点对象。
浏览器的User-Agent字段也很值得分析。我遇到过CDN资源被恶意刷量的情况:某个下载文件被爬虫工具高频请求,每次请求都带着不同的Referer和随机User-Agent,日志里可以明显看到同一IP在秒级时间窗口内连续下载几十次。发现这种异常后,我会及时在CDN上配置访问控制,限制该IP的QPS,并把该下载链接改为URL鉴权模式。
监控告警方面,我自己常用的观察指标有三个:回源失败率(5xx比例)超过某个阈值、命中率下降超过多少个百分点、带宽突增。这三个指标都不能只盯着控制台,建议通过CDN服务商提供的API把数据拉到自建监控系统中,接入现有的告警通知渠道才算真正闭环。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
这几年跟CDN打交道,各种奇葩问题都遇到过。我把出现频率最高、最容易让人一头雾水的问题整理成了一张速查表,建议收藏。
| 问题现象 | 最可能原因 | 快速排查方法 |
|---|---|---|
| 配置CDN后网站打不开 | CNAME未生效或源站地址错误 | 查dig解析结果,检查源站回源设置 |
| 页面更新了,CDN还是旧内容 | 缓存未过期或未刷新 | 手动刷新对应URL,检查缓存策略 |
| 命中率极低,回源率高 | 响应头被设为no-cache,或规则配置不当 | curl -I看响应头,对照缓存规则 |
| 登录后状态丢失或信息错乱 | 动态接口被误缓存 | 确认API路径不在长缓存URL名单之内 |
| HTTPS访问提示证书无效 | CDN节点证书未部署或已过期 | 检查证书绑定和有效期,配置自动续期 |
| 图片能打开但CSS样式丢失 | 缓存策略覆盖导致静态资源过期后返回异常 | 刷新静态资源目录,检查缓存规则优先级 |
| 流量账单异常偏高 | 外链盗刷或资源被大量爬取 | 开启防盗链和URL鉴权,分析访问日志 |
5.2 一条命令定位缓存问题的通用方法
怀疑CDN缓存有问题时,我第一个想到的工具就是curl。用-I参数只取响应头,就能快速判断CDN节点的缓存状态。
curl -I https://static.example.com/css/main.css输出里重点看三个字段:
- HTTP状态码:200表示正常返回,403或404说明访问控制或源站有问题
- Cache-Control: max-age=... :源站设置的缓存时间
- X-Cache或X-Cache-Lookup:HIT表示命中缓存,MISS表示未命中
当X-Cache是MISS时,再往下看响应头里的Via字段,它通常会带上CDN节点的信息和缓存命中的标记。如果多个字段都显示未命中,那基本可以确定问题出在缓存规则或源站响应头上。
另外,想看真实回源效果,可以在源站服务器上直接请求一次相同的资源,对比源站响应时间和CDN节点响应时间。如果源站本身就很慢,那不是CDN的问题,而是源站性能需要优化;如果源站快、CDN慢,则要排查网络链路质量和节点配置问题。
5.3 命中率优化与缓存穿透避坑经验
我在多个项目里把CDN命中率从不到70%提升到了95%以上,核心操作其实就几条。
第一,把不可缓存的响应头改掉。曾经有个项目,后端框架自动给所有响应都加上了Cache-Control: private或no-store,CDN控制台怎么配置缓存规则都不管用。后来我在源站的中间件层写了一个过滤规则,对静态资源路径强制覆盖Cache-Control,问题直接就解决了。这些坑都出在大家都不注意的响应头细节上。
第二,统一URL后缀和目录结构。CDN缓存对URL非常敏感,同一个文件用main.abcd1234.min.js和main.js两个URL访问,会被当作两个独立的缓存项。前端构建工具一般会通过文件名中的hash做版本控制,这种情况下URL本身已经带有唯一性,配置长缓存是很安全的。但要注意多个环境共用同一个CDN域名时,不同版本的文件应该放在不同的路径前缀下,避免缓存污染。
第三,警惕缓存穿透。某次活动期间,大量用户请求一个不存在于源站的图片路径,每次请求都无法命中CDN缓存,导致全部穿透到源站,源站压力大增。排查后发现,页面里有些图片URL是后端动态拼接的,拼接逻辑出bug导致部分路径永远指向同一个不存在的文件。修复了URL拼接逻辑后,源站的异常流量立刻消失了。缓存穿透问题除了从业务侧修复,也可以在CDN侧配置针对404状态码的短时间缓存,比如对404响应缓存60秒,防止同一个失效URL被反复回源查询。
第四,合理利用预热。大促前的核心资源,比如首页大图、主要营销活动页的JS和CSS,在活动开始前批量预热一遍,活动刚开始那几分钟的用户体验会好很多。预热时要控制好源站的并发压力,一次性预热几千个文件,源站可能在短时间内承受较大的请求量,我一般会分批预热,每批控制在几百个URL以内。
5.4 一个真实项目的排查全程记录
分享一个最近遇到的比较典型的排查过程,能帮你建立CDN问题的排查框架。
现象是这样的:某业务官网反馈"图片偶尔加载不出来",用户截图显示图片区域一直转圈。
我先做了两个判断:第一,问题是不是影响所有人?因为我自己的浏览器访问是正常的。我随即用curl加不同IP参数来模拟不同地域访问,还是正常的。这基本排除了CDN节点整体故障的可能。
接着查监控报表,发现最近一段时间,回源带宽明显高于往常,回源错误率也略有上升。进一步查看源站访问日志,发现大量来自CDN节点的请求集中在某几个高热图片上,而这些图片都属于一个最近更换过的目录前缀。原来前端代码改版后,新的图片目录名变了,但源站nginx配置里针对这个新目录的缓存规则没有生效,导致这些图片全部走了无法缓存的规则,每次都回源。
定位到问题的思路是:先看现象面(用户能不能访问)、再看数据面(监控指标有没有异动)、再查配置面(缓存规则是否覆盖新路径)。只要按照这个顺序排查,大部分CDN问题都不会花太长时间。
排查完之后,我把新目录的缓存规则补上,并顺手在源站nginx里加了一个所有静态资源的通用缓存头兜底,之后回源带宽恢复了正常,图片加载问题也再没有出现过。
做CDN排查最忌讳一上来就抓瞎,看到哪里有配置就改哪里。一个靠谱的排查顺序是:先确认影响范围,再看监控数据定位方向,最后回到配置和代码层面找根因。这套思路适用于绝大多数CDN问题,也适用于其他基础设施类问题的排查。
最后分享一个小经验:CDN配置好之后不是一劳永逸的,每隔一段时间就要回来看一眼命中率、回源带宽和告警配置,尤其在每次发版前后。我每次上线新功能时,都会顺手做一次"缓存规则复查"——确认新增的URL路径有没有被已有的缓存规则覆盖到,是不是需要新增规则,需不需要做预热。这些操作加起来不超过十分钟,但能帮你省掉后面一连串的线上故障处理时间。