D1 只读副本存在 6 秒延迟
一个位于东京的 D1 只读副本比北美洲的一次写入操作落后了 6.1 秒。
我从一个因为错误的曝光数据而进行限流的追踪器中发现了这一点。文档提到了最终一致性 (eventual consistency),但并没有给出具体的延迟时间供你进行规划。
我构建了一个陈旧性探测器 (staleness probe) 来获取真实数据。该探测器写入一行包含 UUID 和 epoch 的数据。它会轮询只读副本,直到该行出现,然后记录延迟时间。
在亚洲进行的 200 次探测结果如下:
- p50: 800ms
- p95: 3,400ms
- p99: 6,100ms
如果你的主库在北美,而用户在亚洲,延迟会非常高。
我还遇到了一个 schema 错误。一次迁移在主库上运行,随后一个 Worker 重启。首批请求在同步到新表之前就命中了只读副本。错误提示表不存在。表其实是存在的,只是副本落后了。
我通过绕过延迟来解决这个问题,而不是试图去对抗它。
以下是我的设计方案:
- 写入器在行中添加一个
written_atepoch。 - 写入器在响应中添加一个
X-D1-Written-At请求头。 - 读取器将该请求头与来自副本的数据进行比较。
- 如果副本数据比请求头中的时间更旧,读取器将回退到使用 KV。
在同一区域内,KV 的运行时间在 500ms 以内。每天最多 1000 万次读取是免费的。这为获取关键标志 (critical flags) 的最新数据提供了一种廉价的方式。
你只会在副本落后的短暂窗口期内使用 KV。一旦副本完成同步,大多数读取都会正常命中 D1。
我在详细的文章中分享了完整的脚本和迁移模式。