Write-through はキャッシュとデータベースの整合性を保つため、同期的に両方へ書き込みます。そのため書き込みはデータベースと同等の遅さになります。一方、write-behind は正反対の賭けです。キャッシュへ即座に書き込み、すぐに確認応答を返し、データベースへの永続化は後で非同期に実行します。書き込みはメモリにしか触れないため高速になります。ただし、コミットされた書き込みが Redis 上にしか存在しない期間が生じるため、クラッシュによってそれらが失われる可能性があります。これは最高のパフォーマンスと最高のリスクを伴うキャッシュパターンであり、使用前に何をトレードオフしているかを正確に理解することが不可欠です。
これは Redis Masterclass の第 11 回で、read-through と write-through に続きます。
write-behind の仕組み
write-behind(write-back とも呼ばれる)では、書き込みは Redis へ送られ、すぐに返されます。データベース更新は別途、非同期に他の書き込みとまとめて行われます。
- アプリケーションは Redis へ書き込み、即座に確認応答を受け取ります。
- 書き込みは永続化キューへ追加されます。
- バックグラウンドプロセスがキューを処理し、データベースへ書き込みます。多くの場合、複数の書き込みをまとめて少ないデータベース操作にします。
// write is instant: only touches Redis
await redis.hset(`counter:${id}`, 'value', newValue);
await redis.rpush('write_queue', JSON.stringify({ id, value: newValue }));
// a background worker later batches these into the database
Enter fullscreen mode Exit fullscreen mode
アプリケーションが体感する書き込みレイテンシは Redis への書き込みのみで、サブミリ秒です。データベースは後で書き込みを効率的にバッチ処理するため、多くの小さな書き込みを少ない大きな操作にまとめることで負荷を低減します。
なぜ高速で、なぜリスクがあるのか
高速化の理由は 2 つあります。書き込みがメモリのみに触れることと、バッチ処理によってデータベースのオーバーヘッドを平準化することです。書き込み負荷が高いワークロード(高頻度カウンタ、メトリクス、テレメトリ、ビュー追跡)では、write-behind は同期的にデータベースへ書き込むと圧倒されるような書き込みレートを吸収できます。
リスクも同様に現実的です。確認応答された書き込みとデータベースへの最終的な永続化の間に、データは Redis 内にのみ存在します。この期間に Redis がクラッシュ(または永続化ワーカーが停止)すると、アプリケーションが成功したと伝えられた書き込みであっても失われます。write-behind は耐久性を弱めます。ユーザーに「保存された」と伝えた時点で、実際には永続的に保存されていないのです。これは一部のデータでは許容可能ですが、他のデータでは許容できません。どちらに該当するかを正直に判断することがすべてです。
write-behind が適しているケース
このパターンは、高い書き込みスループットが重要で、最新の書き込みが稀に失われることを許容できるデータに適します。
- アナリティクスとメトリクス: ページビュー、イベント数、テレメトリ。稀なクラッシュで数秒分のカウントが失われても問題にならず、書き込み量が多い場合に有効です。
- 集計カウンタ: いいね数、閲覧数など、カウントが累積値で小さな誤差が自己修正される場合。
- アクティビティ追跡: 最終アクセス時刻、非重要ログ。
これらでは write-behind のスループットが真のメリットとなり、耐久性の弱さも許容できるトレードオフです。共通点は、データ量が多く個々の重要度が低いことです。
write-behind が不適切なケース
書き込みが失われることが重大な問題となるデータでは危険です。
- 金融取引、注文、支払い: これらに write-behind を使用してはいけません。「保存された」が消えることは深刻なバグです。
- ユーザーに「永続的に保存された」と伝えられるもの で、失われた場合に驚かれる可能性があるデータ。
- 他の信頼できる情報源がないデータ: Redis が唯一の書き込み場所だった場合、その喪失は完全な損失です。
ルール: クラッシュ時に直近数秒の書き込みが失われることが実際のインシデントになる場合は、write-behind を使用せず、write-through または通常の cache-aside と同期的なデータベース書き込みを採用し、耐久性の代償として高いレイテンシを受け入れてください。
安全性を高める方法
write-behind を使用する場合、以下の対策でリスクを低減(排除ではない)できます。
- Redis の永続化を有効化(AOF、後述)することで、再起動後も Redis 自体が最近の書き込みを復旧し、損失ウィンドウを縮小します。
- 保留中の書き込みに耐久性のあるキュー(Redis Stream など)を使用し、インメモリ構造より堅牢にします。
- フラッシュ間隔を短く保つことで、未永続化データのウィンドウを小さくします。
- キューの深さを監視し、永続化が遅れているかどうかを把握します。これによりリスクウィンドウの拡大と問題の兆候を同時に検知できます。
これらの対策により write-behind のリスクは低減されますが、同期的なデータベース書き込みと同等の耐久性は得られません。ウィンドウは縮小しますが、閉じることはありません。
write-behind は専門的なツールです。高ボリュームで損失を許容できるデータの最大書き込み速度を、弱い耐久性と引き換えに得るものです。スループットが重要で、稀に失われる書き込みが無害なメトリクス、カウンタ、テレメトリに意図的に使用し、決して失われてはならないデータからは遠ざけてください。判断はデータの価値に基づいて行うべきであり、意識的に決定する必要があります。
次回は refresh-ahead キャッシングを取り上げます。これは、有効期限切れ前にホットキーを更新することでキャッシュミスを完全に回避する別の問題に取り組みます。
重要なポイント
- write-behind は Redis に書き込み、即座に確認応答を返し、データベースへの永続化は後で非同期にバッチ処理します。
- サブミリ秒の書き込みを実現し、バッチ処理によりデータベース負荷を低減するため、高い書き込み量に適します。
- リスクは耐久性にあります。確認応答されたがまだ永続化されていない書き込みは、その期間に Redis がクラッシュすると失われます。
- スループットが重要で、最近の書き込みが失われても許容できるアナリティクス、メトリクス、カウンタに使用します。
- 金融データ、注文、または失われた書き込みが実際のインシデントになるものには使用せず、代わりに write-through を使用します。
よくある質問
write-behind(write-back)キャッシングとは何ですか?
書き込みをキャッシュへ送り即座に返し、データベースはバックグラウンドで非同期に(多くの場合バッチで)更新するパターンです。これにより書き込みは高速になりますが、確認応答された書き込みがキャッシュ内にのみ存在する期間が生じます。
write-behind は write-through とどう違いますか?
write-through はキャッシュとデータベースを同期的に更新するため、書き込みは耐久性がありますが遅くなります。write-behind はキャッシュのみを同期的に更新し、データベースは後で更新するため、書き込みは高速ですが、キャッシュが永続化前にクラッシュすると失われる可能性があります。
write-behind キャッシングはいつ使用すべきですか?
アナリティクス、メトリクス、テレメトリ、集計カウンタなど、高ボリュームで損失を許容できるデータに使用します。書き込みスループットが重要で、稀なクラッシュ時に直近数秒の書き込みが失われても許容できる場合に適します。
write-behind を避けるべきケースは?
金融取引、注文、支払い、またはユーザーに「永続的に保存された」と伝えられるもの。失われた書き込みが実際のインシデントになる場合は、write-through または同期的なデータベース書き込みを使用してください。
write-behind をより安全にするには?
Redis の永続化(AOF)を有効化し、保留中の書き込みを Redis Stream などの耐久性のある構造に保持し、フラッシュ間隔を短くし、キューの深さを監視します。これにより潜在的な損失ウィンドウは縮小しますが、同期的なデータベース書き込みと同等の耐久性は得られません。
参考文献
This article was originally published on amanksingh.com/blog/redis-write-behind.
著者について
Aman Kumar Singh はインド・ノイダを拠点とする Team Lead & Senior Software Engineer で、TypeScript、Next.js、NestJS、PostgreSQL、Redis を用いたフルスタックエンジニアリング、システム設計、本番 SaaS について執筆しています。
- Portfolio: amanksingh.com
- GitHub: amansingh1501
- LinkedIn: amansingh1597
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.