网站运营中,CDN缓存策略和源站动态内容刷新是一对天然矛盾——你想让CDN尽可能多地缓存内容来降低源站压力、加速用户访问,但又怕缓存太久导致用户看到过期的动态数据,比如价格变动、库存更新、订单状态变化。解决这个问题的核心思路就三条:根据内容类型分级缓存、设置合理的TTL过期时间、用主动推送机制替代被动等待过期。下面我把这套方法论从底层逻辑到落地操作,一次性讲透。

一、先搞清楚CDN缓存到底在缓存什么

很多人以为CDN缓存就是把整个网页存一份,其实不是。CDN缓存的本质是对HTTP响应的存储,包括HTML页面、图片、CSS、JS文件、API接口返回的JSON数据等。静态资源比如图片、样式表、脚本文件,天然适合长时间缓存,TTL设几天甚至几个月都没问题。但动态内容就不一样了,比如电商的商品详情页、新闻列表、用户个人中心数据,这些内容频繁变化,缓存时间太长用户看到的就是旧数据。

所以第一步,你必须对网站内容做分类。一般分成三类:纯静态资源(图片、字体、CSS、JS)、半动态内容(页面框架不变但数据区会更新,比如商品列表页)、全动态内容(每次请求都可能不同,比如实时库存查询接口)。分类之后,针对不同类别制定不同的缓存策略,这是所有后续操作的基础。

二、TTL缓存时间怎么设才合理

TTL(Time To Live)就是缓存的存活时间,单位是秒。设太短,CDN频繁回源,等于白用CDN;设太长,用户看到过期内容。实际操作中,我建议这样设:

纯静态资源:TTL设为2592000秒(30天)甚至更长,配合文件名带hash值的版本控制,更新时文件名变化,CDN自动获取新文件。

半动态页面:TTL设为60秒到300秒(1到5分钟)。比如商品详情页,价格和库存可能几分钟变一次,设5分钟TTL,大部分用户看到的是准实时数据,源站压力也可控。

全动态接口:TTL设为0到10秒,或者直接不缓存,每次都回源。比如支付回调接口、实时数据查询接口,这种数据容不得半点延迟。

这里有个实操技巧:不要只设一个统一的TTL,要利用CDN的规则引擎按URL路径、文件类型、请求头来分别设置。比如在CDN控制台里,可以这样配置规则:

规则1:URL匹配 *.jpg *.png *.gif *.css *.js
缓存时间:2592000秒(30天)

规则2:URL匹配 /product/* /news/*
缓存时间:300秒(5分钟)

规则3:URL匹配 /api/stock/* /api/order/*
缓存时间:0秒(不缓存)

大部分主流CDN服务商都支持这种精细化规则配置,花十分钟设好,长期受益。

三、主动刷新比被动过期更重要

被动等TTL过期有个致命问题:在过期之前的这段时间里,用户看到的全是旧数据。比如你刚改了商品价格,但TTL还有3分钟才过期,这3分钟内所有用户看到的还是旧价格,可能引发投诉甚至法律风险。

解决方案就是主动刷新,也叫缓存预热或缓存清除。主流做法有三种:

第一种,URL级刷新。当源站内容更新时,通过CDN的API接口,主动把特定URL的缓存清除掉。比如商品价格改了,立刻调用API清除 /product/12345 这个页面的缓存,下一个用户请求就会回源拿到最新数据。代码示例如下:

// 调用CDN刷新接口示例(以通用REST API为例)
POST https://cdn-api.example.com/v1/purge
Headers:
  Authorization: Bearer your-api-token
Body:
{
  "urls": [
    "https://www.yoursite.com/product/12345",
    "https://www.yoursite.com/product/12346"
  ]
}

第二种,目录级刷新。如果你一次更新了一个分类下的所有商品,可以用通配符刷新整个目录,比如 /product/category/electronics/* ,一次清除几十上百个页面。

第三种,全站刷新。一般只在大版本更新或者缓存策略调整时用,平时不要滥用,因为会瞬间把所有缓存清空,源站压力会飙升。

四、源站如何配合CDN做好动态内容管理

CDN只是中间层,真正的数据源头在你的服务器。源站要做好几件事才能和CDN配合好:

首先,接口响应要带正确的缓存控制头。源站返回的HTTP响应里,Cache-Control和Expires头要和CDN的TTL策略一致。如果源站说缓存1小时,CDN设了5分钟,以CDN为准;但如果源站说不缓存,CDN却缓存了,就会出问题。所以源站代码里要明确设置:

// Node.js/Express 示例
app.get('/api/stock/:id', (req, res) => {
  res.set({
    'Cache-Control': 'no-cache, no-store, must-revalidate',
    'Pragma': 'no-cache',
    'Expires': '0'
  });
  // 查询最新库存并返回
  res.json({ stock: getLatestStock(req.params.id) });
});

app.get('/product/:id', (req, res) => {
  res.set({
    'Cache-Control': 'public, max-age=300',
    'Expires': new Date(Date.now() + 300000).toUTCString()
  });
  // 返回商品页面
  res.render('product', { data: getProductData(req.params.id) });
});

其次,源站要有内容更新的触发机制。比如后台管理员改了商品信息,系统要自动触发CDN缓存清除。这可以通过消息队列来实现:内容更新事件发布到队列,消费者收到消息后调用CDN刷新API。这样从内容变更到缓存清除,延迟可以控制在秒级。

再次,源站要做好回源保护。当CDN缓存大量失效时,会有大量请求同时打到源站,可能把源站打垮。解决办法是在源站前面加一层本地缓存(比如Redis),把热点数据先缓存在内存里,即使CDN回源,也不会直接冲击数据库。

五、几个容易踩的坑和进阶技巧

坑一:忽略了用户登录态。很多网站登录后看到的内容和未登录不一样,如果CDN按URL缓存,可能把登录用户的页面缓存后返回给了未登录用户。解决办法是在CDN配置里,根据Cookie中的登录标识来区分缓存,或者对需要登录才能访问的页面直接设为不缓存。

坑二:HTTPS证书问题。CDN和源站之间的回源请求如果是HTTP,而用户访问是HTTPS,中间链路不安全。现在主流做法是CDN到源站也用HTTPS,但要注意证书配置和SNI支持,否则回源可能失败。

坑三:忽略了CDN节点的地域差异。不同地区的CDN节点缓存可能不同步,用户在A城市看到了新内容,B城市用户还在看旧内容。这个问题没有完美解法,但可以通过缩短TTL和增加主动刷新频率来缓解。

进阶技巧一:使用边缘计算。现在很多CDN支持在边缘节点运行轻量级代码(Edge Function),你可以在边缘节点上做简单的数据处理和缓存逻辑,比如根据用户地区返回不同的内容,进一步减少回源。

进阶技巧二:利用CDN的回源跟随功能。当源站返回302重定向时,CDN可以跟随重定向去获取新地址的内容并缓存,这样你可以通过调整源站的URL结构来间接控制缓存策略,不用频繁调CDN配置。

进阶技巧三:监控和数据驱动优化。给CDN配置好日志和监控,定期分析缓存命中率、回源率、各URL的访问频率。缓存命中率低于80%说明策略太保守,回源率突然飙升说明可能有大量缓存失效,需要排查原因。用数据来调整策略,比拍脑袋设TTL靠谱得多。

六、总结:一套可落地的执行清单

把上面的内容浓缩成可执行的步骤:第一步,梳理网站所有内容类型,分静态、半动态、全动态三类;第二步,在CDN控制台按URL路径和文件类型设置差异化TTL;第三步,开发或接入缓存刷新API,实现内容更新时主动清除;第四步,源站接口设置正确的Cache-Control响应头;第五步,搭建内容变更触发缓存清除的自动化流程;第六步,配置监控告警,持续优化缓存策略。做到这六步,你的网站在CDN加速和内容实时性之间就能找到最佳平衡点。

最后说一句大实话:CDN缓存策略不是设一次就完事的,它需要根据业务变化、流量波动、用户反馈持续调整。没有万能的配置,只有不断迭代的优化。把这件事当成一个长期运营的项目来做,而不是一次性的技术配置,你的网站性能和用户体验才能真正稳得住。