ホームページ >データベース >Redis >Redis キャッシュとデータベース間の一貫性を確保する方法

Redis キャッシュとデータベース間の一貫性を確保する方法

WBOY
WBOY転載
2022-03-17 18:50:153178ブラウズ

この記事では、Redis に関する関連知識を提供します。主に、キャッシュの更新やデータベースの更新など、Redis キャッシュとデータベースの一貫性を確保する方法を紹介します。ヘルプ。

Redis キャッシュとデータベース間の一貫性を確保する方法

推奨される学習: Redis 学習チュートリアル

1. 4 つの同期戦略:

キャッシュの一貫性を確保したいデータベースの二重書き込みでは、4 つの方法、つまり 4 つの同期戦略があります:

  1. 最初にキャッシュを更新してからデータベースを更新する;
  2. 最初にデータベースを更新する、次にキャッシュを更新します。
  3. 最初にキャッシュを削除してから、データベースを更新します。
  4. 最初にデータベースを更新してから、キャッシュを削除します。

これら 4 つの同期戦略のうち、比較する必要があるのは次のとおりです。

キャッシュを更新する方法とキャッシュを削除する方法はどちらがより適切ですか?データベースを最初に操作する必要がありますか、それともキャッシュを最初に操作する必要がありますか?

2. キャッシュを更新するかキャッシュを削除する

次に、キャッシュを更新するか削除するかを分析しましょう。

2.1 更新キャッシュ

利点:キャッシュはデータが変更されるたびに適時に更新されるため、クエリ中にミスが発生する可能性が低くなります。

デメリット:キャッシュの更新には多額の費用がかかります。データをキャッシュに書き込む前に複雑な計算を行う必要がある場合、キャッシュを頻繁に更新するとサーバーのパフォーマンスに影響します。データが頻繁に書き込まれるビジネス シナリオの場合、キャッシュが頻繁に更新されるとデータを読み取るビジネスがなくなる可能性があります。

2.2 キャッシュの削除

メリット:操作が簡単、更新操作が複雑でも、キャッシュ内のデータは削除されません。直接削除されます。

欠点:キャッシュを削除すると、次のクエリ キャッシュが失われるため、データベースを再度読み取る必要があります。上記の比較から、一般に、キャッシュを削除する方が良い解決策となります。

3. データベースとキャッシュを先に操作する

次に、データベースとキャッシュのどちらを先に操作するべきかを分析してみましょう。
まず、最初にキャッシュを削除し、最初にデータベースを更新し、障害が発生した場合の比較を行います。

3.1 最初にキャッシュを削除し、次にデータベースを更新します

Redis キャッシュとデータベース間の一貫性を確保する方法
上記のように、キャッシュが削除されてからデータベースが更新される 障害が発生した場合に発生する可能性がある問題:

  • スレッド A はキャッシュの削除に成功しましたが、スレッド A はデータベースの更新に失敗します。
  • スレッド B はキャッシュからデータを読み取ります。キャッシュが削除されているため、プロセス B はキャッシュからデータを取得できず、データベースからデータを読み取ります。この時点ではの場合、データベース内のデータの更新は失敗しますが、スレッド B はデータベースから古いデータを正常に取得し、データはキャッシュに更新されます。
  • 最終的に、キャッシュとデータベースのデータは一貫していますが、古いデータのままです
#3.2 最初にデータベースを更新してから削除しますキャッシュ

Redis キャッシュとデータベース間の一貫性を確保する方法 上に示すように、最初にデータベースが更新されてからキャッシュが削除されます。
が失敗した場合に発生する可能性がある問題:

    スレッド A はデータベースを正常に更新し、スレッド A はキャッシュの削除に失敗しました;
  • スレッド B はキャッシュを正常に読み取りました キャッシュの削除に失敗したため、スレッド B はキャッシュ内の古いデータを読み取りました。
  • 最後に、スレッド A はキャッシュを正常に削除し、他のスレッドはキャッシュ内の同じデータ (データベース内のデータと同じ) にアクセスします。
  • 最終的には、キャッシュとデータベースのデータに一貫性が保たれますが、一部のスレッドは古いデータを読み取ります。
上記の比較の結果、

障害が発生した場合、キャッシュを削除するのが先か、データベースを更新するのが先か、どちらの方法が優れているかを明確に区別することはできないことがわかりました。 、どちらも優れていると考えていますが、問題があります。これら 2 つの方法については後でさらに比較しますが、ここではまず、上記のシナリオで発生する問題を解決する方法について説明します。

実際、キャッシュとデータベースの同期に上記のどの方法を使用しても、2 番目のステップが失敗した場合は、

再試行メカニズムを使用して問題を解決することをお勧めします。上の2枚の写真はすでに塗装済みです。



次に、最初にキャッシュを削除し、最初にデータベースを更新し、障害がない場合の
を比較します。

次のように上記では、最初にキャッシュが削除され、次にデータベースが更新されます。
が失敗しない場合、Redis キャッシュとデータベース間の一貫性を確保する方法 考えられる問題:

  • スレッド A はキャッシュの削除に成功しました;
  • スレッド B はキャッシュの読み取りに失敗しました;
  • スレッド B はデータベースの読み取りに成功し、古いデータを取得しました;
  • スレッド B は古いデータをキャッシュに正常に更新しました;
  • スレッド A は新しいデータをデータベースに正常に更新しました。

プロセス A の 2 つのステップは成功しましたが、同時実行により、プロセス B が 2 つのステップの間にキャッシュにアクセスしたことがわかります。 最終的に、古いデータはキャッシュに保存され、新しいデータはデータベースに保存され、2 つのデータは矛盾します。



Redis キャッシュとデータベース間の一貫性を確保する方法
上記のように、最初にデータベースが更新され、その後キャッシュが削除されます。 が失敗しない場合、 考えられる問題:

  • スレッド A はデータベースを正常に更新します;
  • スレッド B はキャッシュを正常に読み取ります;
  • スレッド A はキャッシュを正常に削除します。

最終キャッシュはデータベース内のデータと一致しており、両方とも最新のデータであることがわかります。ただし、スレッド B はこのプロセス中に古いデータを読み取ります。これら 2 つのステップの間にキャッシュ内の古いデータを読み取るスレッド B のような他のスレッドが存在する可能性がありますが、これら 2 つのステップの実行速度が速いため、影響はありません。大きい。この 2 つの手順を実行すると、他のプロセスがキャッシュされたデータを読み出すときに、プロセス B のような問題は発生しなくなります。

最終結論:

比較すると、最初にデータベースを更新してからキャッシュを削除するのが影響の少ない解決策であることがわかります。 2 番目のステップが失敗した場合は、再試行メカニズムを使用して問題を解決できます。

4. 遅延二重削除

上で述べたように、

最初にキャッシュを削除してからデータベースを更新すると、問題が発生する可能性があります。データの不整合。実際のアプリケーションで、何らかの考慮事項によりこの方法を選択する必要がある場合、この問題を解決する方法はありますか?答えは「はい」です。それは、遅延二重削除戦略を採用することです。遅延二重削除の基本的な考え方は次のとおりです:

キャッシュを削除します。
  1. データベースを更新します;
  2. N ミリ秒スリープします;
  3. キャッシュを再度削除します。
  4. 	public void write(String key, Object data) {
            Redis.delKey(key);
            db.updateData(data);
            Thread.sleep(1000);
            Redis.delKey(key);
        }
一定期間ブロックした後、再度キャッシュを削除して、キャッシュ内の矛盾したデータを削除します

。具体的な時間については、業務のおおよその時間を評価し、それに応じて設定する必要があります。 4.1 読み取り/書き込み分離アーキテクチャを採用する場合はどうすればよいですか?

データベースが読み取りと書き込みの分離アーキテクチャを採用している場合、以下に示すように、新たな問題が発生します。


この時点で、A (更新操作) を要求する 2 つのリクエストが来ました。そしてリクエスト B (クエリ操作) Redis キャッシュとデータベース間の一貫性を確保する方法

Request A update Operation, delete Redis;
  1. メイン ライブラリに更新操作の実行をリクエストし、メイン ライブラリとスレーブ ライブラリの同期をリクエストしますデータ ;
  2. B にクエリ操作を依頼して、Redis にデータがないことがわかりました;
  3. データベースからデータを取得してください;
  4. この時点で、データの同期が完了しておらず、取得されたデータは古いデータです;
  5. 現時点での解決策は、Redis を使用してデータを埋めるためにデータベースにクエリを実行する場合、強制的にクエリ用のメイン データベースを指します。

削除に失敗した場合はどうすればよいですか?

それでも削除に失敗する場合は、再試行回数を増やすこともできますが、一定の回数を超えた場合は、エラーの報告、ログの記録、メールによるリマインダーの送信などの措置を講じる必要があります。取らなければなりません。

5. メッセージ キューを使用して削除を補う

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

この状況でも問題が発生します。たとえば、データベースが更新されます。成功しましたが、キャッシュ削除の段階でエラーが発生して削除が成功しなかった場合、この時に再度キャッシュを読み込むと、毎回データが間違ってしまいます。
Redis キャッシュとデータベース間の一貫性を確保する方法現時点での解決策は、メッセージ キューを使用して削除を補うことです。特定のビジネス ロジックは次の言語で説明されています:

スレッド A に最初にデータベースを更新するよう要求します;
  1. Redis の削除時にエラーが報告され、削除に失敗しました;
  2. このとき、Redis キーがメッセージ本文としてメッセージ キューに送信されます;
  3. システムは、メッセージ キューによって送信されたメッセージを受信した後、再度 Redis を削除します;
  4. しかし、このソリューションには、ビジネス コードへの侵入が多くなり、相互に深く結合されるという欠点があるため、現時点では最適化方法が用意される予定です。Mysql データベースは で更新されることがわかっています。操作後の binlog 対応する操作をすべて見つけることができ、Mysql データベースの binlog ログをサブスクライブしてキャッシュを操作できます。


Redis キャッシュとデータベース間の一貫性を確保する方法 推奨学習:

Redis チュートリアル

以上がRedis キャッシュとデータベース間の一貫性を確保する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。