Phil Karlton 表示,计算机科学中只有两件难事:缓存失效和命名。 KV 使第一个变得更加困难,因为您无法控制失效何时到达每个存在点。
删除 KV 中的密钥并不会立即将其从世界中删除。删除操作将发送到中央存储并以与写入相同的最终一致性动态传播到 PoP:最多 60 秒即可到达所有存在点。在此窗口期间,尚未收到删除的 PoP 会继续为任何传入请求提供旧值。您不知道哪些 PoP 收到了它,哪些没有收到。没有办法强制立即传播。
这使得KV中的缓存失效成为一个设计问题,而不是操作问题。您不能通过“立即无效”按钮来解决它 - 您可以通过选择一个能够最大限度地减少传播延迟影响的关键模型来解决它。
版本化密钥:最强大的解决方案
对于需要失效的内容,最可靠的标准是在数据的逻辑名称和存储数据的物理密钥之间保持显式的间接关系。
您不必将页面呈现的 HTML 写入 0 ,然后在内容更改时将其删除,而是将其写入 1 。第二个键2仅包含字符串3。 Worker首先读取版本密钥,构造内容密钥名称,并获取值。
当内容发生更改时,您可以在4中写入新的HTML,并将5更新为6。旧密钥不需要立即删除——它只是停止被引用。它的存储成本将继续存在,直到您进行清理,但失效不一致不再是问题:任何收到 7 更新的 PoP 都已经获得了新密钥。旧内容仅提供给尚未收到版本密钥更新的 PoP,无论您做什么,这都会在 60 秒窗口内发生。
这种方法的成本是每个请求一次额外的读取——首先是版本密钥,然后是内容。在大多数情况下,这个成本与延迟无关:如果 Worker 使用 8 进行读取,则两次读取是并行的,并且在热时都在亚毫秒内从 PoP 缓存到达。
协调 KV 与 CDN 清除
对于从 Cloudflare CDN(而不是直接从 Worker)提供的内容,在 KV 之上还有一个额外的缓存层。 CDN可能已经缓存了使用旧KV值生成的响应,即使KV在所有PoP中已经具有新值,CDN中缓存的响应仍然会被提供直到其过期。
解决方案是将 KV 更新与 CDN 清除协调起来。 Cloudflare 的缓存清除 API 允许您通过 API 使特定 URL 或缓存标签失效。您将新值写入 KV,并在同一管理操作中为受影响的 URL 调用清除 API。从通过 CDN 的客户的角度来看,新的响应在清除后立即出现 - 无论有多少 PoP 仍在传播 KV 值。
此模式要求您控制内容更新过程并有权访问清除 API。对于发布者发布内容的 CMS 流,这是一个合理的集成:发布 Webhook 更新 KV 并触发清除。
使用 waitUntil 重新验证时过时
stale-while-revalidate 模式在触发后台更新时提供可能过时的内容。在 Workers 上下文中,9 允许在响应发送到客户端后执行异步工作。
典型实现:Worker读取当前KV值,立即服务。同时,它通过 10 触发一个函数,检查该值是否需要更新(例如,咨询来源),并在必要时将新值写入 KV。客户端接收响应而不等待更新。下一个请求可能已经收到新值,具体取决于传播完成的时间。
权衡是明确的:您用客户端的零延迟换取可以提供过时内容的窗口。对于大多数内容缓存场景,这种权衡是可以接受的。对于过时会产生运营后果的数据(价格、库存可用性、访问权限),该标准是不合适的。
TTL 作为显式失效的替代
对于不需要精确失效的情况,TTL 是最简单的机制。 KV 支持撰写本文时定义的11(从现在起的秒数)和12(Unix 时间戳)。
TTL 为 60 秒的功能标志会自动过期。过期后的下一个请求将获取中央存储并返回最新值 - 或一个空值,Worker 可以将其解释为“标记已禁用”。您不需要显式删除或跟踪状态。
对于具有可预测刷新频率的内容,刷新周期对齐的 TTL 消除了主动失效的需要。每次生成的报告的TTL可以为3600秒。任何用户将看到的最旧的可能值大约是一小时,这是一种设计选择,而不是一致性缺陷。
不起作用:立即删除并重写
一种经常出现但不能解决问题的模式是删除旧密钥并按顺序写入新密钥。这并不能消除不一致窗口——两个操作独立地传播到 PoP。 PoP 可能会收到删除,但尚未收到新的写入,并且在该窗口期间,它将返回未找到该密钥。根据工作人员处理这种情况的方式,这可能会导致错误或意外的回退。
删除和重写具有双倍的传播操作和三倍可能的中间状态:旧的、未找到的、新的。版本控制或 TTL 密钥始终是首选。
最终一致性如何改变设计
使用 KV 的最健康模式是接受最终一致性作为系统的一个特性,而不是作为需要解决的限制。这意味着设计流程时可以容忍最多 60 秒的不一致窗口,而如果不能容忍,则使用不同的工具。
对于需要在所有 PoP 之间立即保持一致性的数据,KV 并不是合适的工具。 D1 的读数定向到主数据库,或用于具有序列化访问状态的持久对象,涵盖了 KV 最终一致性模型不起作用的情况。
KV 中的优雅失效并不需要紧急发生——因为系统设计是为了容忍传播窗口。任何强制立即一致性的尝试都会对架构产生不利影响,而不是与之相悖。
另请阅读
- [Cloudflare KV:当你需要写时,全球分布式意味着什么13
- [速率限制、功能标志和分布式配置的 KV:它在哪里起作用以及在哪里失效14
- [生产中的 KV:有效的模式和一开始就具有欺骗性的模式15
- [KV、R2 与 Cache API:何时使用每个 Cloudflare16 存储层
- [只有工人才能做的事情,只有页面才能做的事情以及两者相遇的地方17
- [Cloudflare D1:边缘的 SQLite 数据库 — 以及为什么“边缘”的含义并不像看上去的那样18
