Redisとデータベースの同期の問題

キャッシュはデータベースとして機能します

たとえば、非常に頻繁にアクセスされるSessionは、このソリューションに適しています。もちろん、データベースが含まれていないため、整合性の問題は発生しません。

キャッシュはデータベースのホットスポットキャッシュとして機能します

読み取り操作

現在の読み取り操作には、次のような固定ルーチンがあります。

  1. クライアントがサーバーを要求するときに、サーバーのキャッシュで見つかった場合は、サーバーを直接フェッチします。

  2. キャッシュに存在しない場合は、データベースを要求し、データベースによって計算されたデータをキャッシュに埋め戻します。

  3. クライアントにデータを返します。

書き込み操作

さまざまな状況により、データベースとキャッシュの間に不整合が生じます。これは、キャッシュとデータベースの二重書き込みの整合性の問題です。

現在、キャッシュには3つの戦略があります。

  • キャッシュアサイド更新戦略:キャッシュとデータベースを同時に更新します。

  • 読み取り/書き込みによる更新戦略:最初にキャッシュを更新します。キャッシュはデータベースを同期的に更新します。

  • Write Behind Caching更新戦略:最初にキャッシュを更新し、データベースを定期的および非同期的に更新します。

3つの戦略にはそれぞれ長所と短所があり、ビジネスシナリオに応じて使用できます。

キャッシュアサイド更新戦略

この戦略の一般的なプロセスは、リクエストが着信したときにキャッシュからフェッチすることです。リクエストがキャッシュにヒットすると、読み取られたデータが直接返されます。逆に、ヒットがない場合、データは正常に取得されます。データベースから取得し、キャッシュをクリアします。データ。具体的なフローチャートは次のとおりです。

 

しかし、上記はいくつかの特別な場合の問題です:

質問1:最初にデータベースを更新してから、キャッシュを更新します

同時実行性が高い場合、2つのスレッドがダーティデータを読み取る可能性があります。

  1. スレッドAは書き込み操作を実行し、データベースを正常に更新します。

  2. スレッドBもスレッドAと同じ操作を実行しますが、スレッドAによってキャッシュを更新するプロセスで、スレッドBは新しいデータベースデータをキャッシュに更新します。

  3. スレッドAは、スレッドBのすべての操作が完了した後、比較的古いデータをキャッシュに更新します。

質問2:最初にキャッシュを削除してから、データベースを更新します

同様に、ダーティリードは同時実行性の高いシナリオでも発生します。

  1. スレッドAはキャッシュを正常に削除し、データベースの更新を待機しています。

  2. スレッドBは読み取り操作を実行します。この時点でキャッシュが削除されているため、スレッドBはデータベースから古いデータを取得し、それをキャッシュに更新します。

  3. スレッドAは、スレッドBが読み取り操作全体を完了した後にのみデータベースを更新します。この時点では、キャッシュ内のデータは引き続き古いデータです。

 

質問3:最初にデータベースを更新してから、キャッシュを削除します

現在、これは比較的一般的な操作ですが、まだダーティな読み取りである可能性があります。

  1. スレッドAは読み取り操作を実行しますが、この時点でキャッシュを見逃してから、データベースを要求します。

  2. スレッドBは書き込み操作を実行します。スレッドAはデータベースからデータを取得する前に、データをデータベースに書き込み、キャッシュを正常に削除します。

  3. スレッドBが書き込み操作全体を完了した後、スレッドAは比較的古いデータをキャッシュに更新します。

ただし、上記の状況は発生しません。これは、スレッドAの読み取り操作がスレッドBの書き込み操作よりも遅いことを上記の状況で満たす必要があるためですが、実際には、通常、読み取り操作は書き込み操作よりもはるかに高速です。 。ただし、上記の状況を回避するには、通常、キャッシュに有効期限を追加する必要があります。

しかし、上記のキャッシュの削除が失敗した場合、明らかにデータの読み取りがダーティになる状況になると想像してみてください。計画は次のとおりです。

  1. キャッシュの有効期限を設定します(実行する必要があります)。

  2. 削除に失敗したキーが消費のためにメッセージキューに提供される保証再試行メカニズムを提供します。

  1. これらのキーをメッセージキューから削除し、再度削除します。失敗した場合は、メッセージキューに再度追加されます。特定の回数を超えると、手動による介入が発生します。

 

 

ただし、上記の状況はビジネスコードで操作する必要があり、明らかに分離する必要があります。

現在、当社はこのソリューションを使用しています。具体的なプロセスは、データベースデータが更新されると、データベースがbinlogログの形式で保存されることです。binlogは、プログラミング言語を解析できるポイントに解析されます。canalオープンソースソフトウェア、サブスクリプションプログラムがデータを取得します。今後、キャッシュ操作を削除してみてください。操作が失敗した場合は、メッセージキューに追加して繰り返し使用してください。削除操作の失敗回数に達したとき一定の回数でも、手動による介入が必要です。

 

更新戦略による読み取り/書き込み

このモードでは、プログラムはキャッシュを維持するだけでよく、データベースの同期はキャッシュに転送され、更新が同期されます。

戦略は2つの特定のタイプに分けられます:

  1. リードスルー:クエリ中にキャッシュを更新します。

  2. ライトスルー:書き込み操作中にキャッシュがヒットした場合、キャッシュは直接更新され、データベースはキャッシュ自体によって更新されます。

 

キャッシング更新戦略の背後に書き込む

この戦略は、キャッシュを更新するだけで、データベースをすぐには更新しません。特定の時間に非同期でデータベースをバッチで操作するだけです。これの利点は、キャッシュが直接操作されることです。これは非常に効率的であり、操作データは非同期であり、複数の操作データベースステートメントを1つのトランザクションにマージして一緒に送信することもできるため、効率は非常に客観的です。

ただし、この戦略では強力なデータ整合性を実現できず、データベースに更新する必要があるものと、キャッシュに格納するだけのものを確認する必要があるため、実装ロジックは比較的複雑です。

比較する

現在、これは通常、最初にデータベースを更新してからキャッシュを更新する最初の戦略で使用されます。他の戦略は、比較して実装がより複雑です。

最後に言いたいのは、キャッシュは強力な整合性を犠牲にしてパフォーマンスを向上させることを目的としているため、一定の遅延時間が必要です。最終的なデータの整合性を確保するだけで済みます。

おすすめ

転載: blog.csdn.net/qq_36802726/article/details/105687698