D1のリードレプリカに6秒のラグが発生

東京のD1リードレプリカが、北米での書き込みに対して6.1秒遅延しました。

これは、誤ったインプレッションをスロットリングしているトラッカーから知りました。ドキュメントには結果整合性(eventual consistency)について記載されていますが、計画を立てるための具体的な時間は示されていません。

実態を把握するために、データの鮮度を測定するプローブ(staleness probe)を作成しました。このプローブは、UUIDとエポック(epoch)を含む行を書き込みます。そして、その行が現れるまでレプリカをポーリングし、その遅延時間を記録します。

アジアでの200回のプローブ結果:

プライマリが北米にあり、ユーザーがアジアにいる場合、このラグは非常に大きくなります。

また、スキーマエラーにも直面しました。プライマリでマイグレーションを実行した後、Workerが再起動しました。最初の数リクエストが、新しいテーブルが反映される前にレプリカに到達したのです。エラー内容は「テーブルが存在しない」というものでした。テーブル自体は存在していましたが、レプリカの同期が遅れていました。

私はラグと戦うのではなく、ラグを回避するようにルーティングすることでこれを解決しました。

私の設計は以下の通りです:

  1. ライター(writer)が、行に written_at エポックを追加する。
  2. ライターが、レスポンスに X-D1-Written-At ヘッダーを追加する。
  3. リーダー(reader)が、そのヘッダーとレプリカからのデータを比較する。
  4. レプリカのデータがヘッダーよりも古い場合、リーダーは KV にフォールバックする。

KVは同じリージョン内であれば500ms未満で動作します。また、1日あたり最大1,000万回の読み取りまで無料です。これにより、重要なフラグに対して最新のデータを取得するための安価な手段が得られます。

KVを使用するのは、レプリカが遅延している短い期間のみです。レプリカの同期が完了すれば、ほとんどの読み取りは通常通り D1 に行われます。

詳細な記事の中で、スクリプトの全文とマイグレーションのパターンを公開しています。

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