D1 只读副本存在 6 秒延迟

一个位于东京的 D1 只读副本比北美洲的一次写入操作落后了 6.1 秒。

我从一个因为错误的曝光数据而进行限流的追踪器中发现了这一点。文档提到了最终一致性 (eventual consistency),但并没有给出具体的延迟时间供你进行规划。

我构建了一个陈旧性探测器 (staleness probe) 来获取真实数据。该探测器写入一行包含 UUID 和 epoch 的数据。它会轮询只读副本,直到该行出现,然后记录延迟时间。

在亚洲进行的 200 次探测结果如下:

如果你的主库在北美,而用户在亚洲,延迟会非常高。

我还遇到了一个 schema 错误。一次迁移在主库上运行,随后一个 Worker 重启。首批请求在同步到新表之前就命中了只读副本。错误提示表不存在。表其实是存在的,只是副本落后了。

我通过绕过延迟来解决这个问题,而不是试图去对抗它。

以下是我的设计方案:

  1. 写入器在行中添加一个 written_at epoch。
  2. 写入器在响应中添加一个 X-D1-Written-At 请求头。
  3. 读取器将该请求头与来自副本的数据进行比较。
  4. 如果副本数据比请求头中的时间更旧,读取器将回退到使用 KV。

在同一区域内,KV 的运行时间在 500ms 以内。每天最多 1000 万次读取是免费的。这为获取关键标志 (critical flags) 的最新数据提供了一种廉价的方式。

你只会在副本落后的短暂窗口期内使用 KV。一旦副本完成同步,大多数读取都会正常命中 D1。

我在详细的文章中分享了完整的脚本和迁移模式。

来源:https://dev.to/riversea/d1-read-replicas-returned-stale-data-for-6-seconds-heres-what-i-measured-and-how-i-designed-mme