仕組み
ここでの整合性は、複数の場所から読んだデータや、更新後に読んだデータが、どのように一致するかという性質です。
DB、読み取り用レプリカ、アプリケーションキャッシュ、CDNに同じ情報があると、更新の反映時刻がずれることがあります。
6番のキャッシュが「どう再利用するか」の話なら、こちらは古い値を返すことが、業務上許されるかという話です。
代表的な考え方
| 考え方 | 保証したいこと |
|---|---|
| 強い整合性の代表例である線形化可能性 | 各操作が、開始から完了までのある一瞬に実行されたかのように見え、先に完了した操作の順序も保たれる |
| 結果整合性 | 更新が止まり、同期が進めば、最終的に値が一致する |
| Read-your-writes | 自分が行った更新を、その後の自分の読み取りで確認できる |
たとえば線形化可能な在庫データでは、ほかの更新がなければ、在庫の更新完了後に始めた読み取りは、その更新を反映した値を返します。線形化可能性の原論文
補足
ここでは整合性モデルの要点だけを説明しています。線形化可能性だけで、注文作成と在庫更新をまとめて確定できるわけではありません。また、DBで保証される性質がキャッシュ経由の読み取りにも当てはまるとは限りません。どの操作と読み取り経路を保証の対象にするか、個別に確認が必要です。
結果整合性という言葉だけでは、「必ず何秒以内に一致するか」は分かりません。時間上限が必要なら、別途要件と仕組みを定めます。
具体例:商品一覧と注文確定
商品一覧に「在庫あり」と表示されていても、購入までの間に他の人が最後の1個を買うことがあります。
この場合、次のように分けて考えられます。
商品一覧の表示
→ 許容できる範囲でキャッシュを使う
注文確定
→ 在庫を確保する処理で、競合を防ぐ
注文時に単に在庫を読み直すだけでは、2人が同時に「残り1個」を読む可能性があります。
たとえば、在庫を条件付きで減らす操作が必要です。
UPDATE products
SET stock = stock - 1
WHERE id = :product_id
AND stock > 0
RETURNING stock;
このSQLでは、更新できたかどうかで確保の成否を判断します。注文作成との一貫性も必要なので、同じDB内ならトランザクションなどと組み合わせます。
キャッシュ削除だけでも、競合は残る
典型的なCache-Asideでは、読み取り時にキャッシュを確認し、なければDBから取得します。更新時にはDBを書き換え、該当キャッシュを無効化します。
ただし、これだけでDBとキャッシュの厳密な一致が保証されるわけではありません。Microsoft:Cache-Aside
たとえば、次の順序が起こり得ます。
A:DBから古い値を読み取る
B:DBを新しい値に更新する
B:キャッシュを削除する
A:先ほど読んだ古い値をキャッシュへ保存する
削除した後に、古い値が戻ってしまいます。DBのレプリカが遅れている場合も、古い値を再びキャッシュすることがあります。Microsoft:キャッシュと結果整合性
使い分けの判断基準
「キャッシュで十分」と判断するには、次を具体化します。
- 古い情報を見せると、利用者にどんな影響があるか。
- どれくらいの古さまで許容できるか。
- 更新した本人には、直後から新しい値を見せる必要があるか。
- 重要な操作を確定する際、どこで正しさを保証するか。
ランキング表示、プロフィール編集、在庫確保では、求める保証が異なります。許容時間を一律に決めるのではなく、操作ごとに要求を分けます。
設計上の要点
すべての読み取りを最新にするかどうかではなく、古い値を許せる場所と、正しさを保証すべき操作を明確にします。