发布一篇文章后,缓存系统如何联动:CDN、KV 与搜索索引的失效编排
摘要
专讲博客发布后的完整编排:摘要、公开快照、搜索索引、KV 缓存、CDN Purge 分别在什么时候更新。
我之前已经分别写过两篇缓存相关的文章:
两篇把技术点拆开讲清楚了,但真实业务里的缓存编排是另一件事。
点下发布按钮后,摘要、公开内容、搜索索引、KV 缓存、CDN 缓存,到底谁先更新、谁后失效、谁该精准删、谁该批量 bump 版本?
这篇专门讲这个。
从“发布按钮”开始看整条链路
先看一篇文章从发布到前台可见,背后实际发生了什么:
先清缓存再更新索引,用户就可能读到半新半旧的数据。应当:先把公开内容和搜索索引准备好,再做缓存失效。
失效策略分层
这个项目里至少有四种不同的失效策略:
对象 | 策略 | 原因 |
|---|---|---|
单篇文章详情 | 精准删除一个 KV Key | 影响范围小,直接删最便宜 |
文章列表 | bump 版本号 | 列表页组合太多,逐个删不现实 |
标签列表 | 删除固定 Key | 这是一个单 Key 的公共缓存 |
CDN 页面 / API | Purge URL + Prefix | 让边缘节点立刻失效 |
单篇详情为什么适合精准删除
单篇文章页的 KV 缓存是带具体 slug 的,所以更新一篇文章时,我只删这一条:
这类缓存的特点是:
Key 可预测
影响范围小
删除成本低
所以没必要为了“一致性美观”强行上版本号。
首页、归档页、分页列表等都依赖“文章集合”。
逐个删除缓存会遇到这些问题:
你未必知道所有被影响的列表 URL
就算知道,删除操作也会越来越贵
很难保证没有漏网之鱼
所以这里我直接 bump posts:list 的版本号:
新版本号会指向新 key,旧缓存逻辑上就失效了。
标签列表是一个固定 key 的公共缓存,直接删除即可:
漏掉这一步,会导致文章更新了,但标签页和计数还是旧的。
CDN 层要清的,不只是文章详情页
一篇文章的变更会影响好几个入口,实际要清的是这些:
把所有可能受影响的公共入口一次清掉:
文章详情页会变
单篇文章 API 会变
首页和列表页可能因为发布时间、摘要或标题变化而变
搜索页的数据源可能会变
标签页可能会变
这条工作流里,搜索索引也是缓存编排的一部分
搜索也是发布后需同步更新的公开读路径。
所以在 PostProcessWorkflow 里,我把搜索索引更新放在缓存失效之前:
CDN 失效后,详情页、列表页和搜索结果能近乎同步变新。
公开快照也是“缓存系统”的一部分
高亮代码后的公开内容快照,也是面向读路径的预处理结果。
不是所有层都能做到强一致
业务系统里的缓存很少做到所有层同时失效。
比如相关文章接口在 CDN 层会跟着文章一起 Purge,但它内部还有自己的服务端缓存策略,并不是所有读路径都统一挂在同一个版本号命名空间上。
这不是 bug,是 trade-off。工程上要的是足够新、足够稳、足够便宜,不是为了理论完美把每一层都绑成同一种失效机制。
未来发布时间和下架,也要走自己的分支
发布的两个边界处理:
未来发布时间
如果文章状态已经是 published,但发布时间在未来,搜索索引不会立刻更新,而是交给定时发布那条链路处理。
下架文章
文章下架时,工作流会走另一条分支:
从搜索索引里删除
失效相关缓存
删除 sync hash
这和更新文章逻辑不同。
为什么我越来越觉得“缓存”本质上是在编排发布流程
在真实项目里,缓存更像一套发布编排系统:
什么时候生成公开快照
什么时候生成摘要
什么时候更新搜索索引
什么时候删单 Key
什么时候 bump 版本
什么时候 Purge CDN
拆开都不难,难的是让它们按正确顺序一起工作。
