MySQLとRedisがデータの一貫性を確保する方法について説明します。
前置き
キャッシュの高い並行性と性能は様々なプロジェクトで広く利用されているので、このキャッシュの読み込みという側面は基本的に同じで、おそらく以下の図のような流れになると思われます。
しかし、キャッシュの更新という点では、データベースを更新した後にキャッシュを更新した方がいいのか、それともキャッシュを削除すればいいのでしょうか?それとも、キャッシュを削除してからデータベースを更新したほうがいいのでしょうか?現時点では模索する価値がありそうです。
一貫したソリューション
実際のプロジェクト開発では、データベースとキャッシュのデータが一貫していることを確認する必要があります。そうでなければ、人々が100ドルをトップアップして更新し続けても、0.01ドルを表示するのは厄介ではないでしょうか?理論的には、キャッシュに有効期限を設定することは、データの一貫性を確保するための究極の解決策です。このソリューションでは、すべての書き込み操作はデータベースに基づいて行われ、データベースの書き込みが成功してもキャッシュの更新が失敗した場合、キャッシュは自然にデータベースの新しい値を読み、有効期限後に読み込まれたときにキャッシュを更新します。次に、キャッシュの有効期限設定に頼らずに、いかにしてデータの一貫性を確保するかというアイデアがある。ここでは、主に3つの選択肢を検討する。
<ブロッククオート
1) まずデータベースを更新し、次にキャッシュを更新する
キャッシュを削除してから、データベースを更新する。
先にデータベースを更新し、その後キャッシュを削除する。
最初にデータベースを更新し、次にキャッシュを更新します。
この解決策は(私の知る限り~)一般的に反対されていますが、なぜですか?なぜこの選択肢は反対されるのでしょうか?主な理由は2つあり、それについて詳しく説明します。
まず、データセキュリティの観点から、Aの要求とBの要求が同時にあり、Aが先にデータベースのデータを更新し、すぐにBがそのデータを更新した場合、おそらくネットワークの遅延などの理由で、AよりBが先にキャッシュを更新した場合、その後どうなるでしょうか。キャッシュのデータはBが更新した最新のデータではないので、データの不整合が発生します。
次に、ビジネスシナリオの面では、データベースへの書き込みが多く、読み込みが少ないビジネスの場合、このソリューションを使うと、キャッシュを読み込む前にデータが頻繁に更新されることになり、パフォーマンスを無駄にすることになります。
キャッシュを削除してからデータベースを更新するのか、データベースを更新してからキャッシュを削除するのか、次の2つのシナリオがより議論を呼ぶでしょう。
データベースを更新する前にキャッシュを削除する場合
Aの更新要求とBの問い合わせ要求が同時にあった場合、Aが書き込み操作を要求する前にキャッシュを削除し、ちょうどその時にBが入ってきてキャッシュが空であることに気づき、Bがデータベースに問い合わせ、Aの書き込み操作がまだ完了していなければBは古い値をまだ問い合わせるか、古い値をキャッシュに書き込み、Aが新しい値をデータベースに書き込むということが起こる可能性があるのだそうです。キャッシュに有効期限を設けない場合、データは常にダーティになります。
この状況を解決するには、遅延二重削除戦略を使用します。これは、データベースを更新する前にキャッシュを削除し、その後データベースに書き込み、データベースの更新後に再びキャッシュを削除することで、読み取り要求によって引き起こされる可能性のあるキャッシュされたダーティデータを削除する方法です。このようにする目的は、読み取り要求が終了し、書き込み要求が読み取り要求によって引き起こされたダーティデータを削除できるようにするためである。MySQLは、読み取り/書き込みアーキテクチャを使用している場合、データの不整合は、マスタースレーブの遅延によって引き起こされる可能性があり、これはマスタースレーブ遅延時間ハイバネーションによると書き込み操作の完了後に行うことができますし、キャッシュ操作を削除することができます。遅延二重削除の疑似コードは、次のとおりです。
# Pseudocode
def delay_delete():
redis.delete('name') # delete the cache before updating the database
sql = 'update info set name='lili' where id=1;' # update database
cursor.execute(sql)
time.sleep(1) # If mysql is a master-slave architecture then sleep the master-slave delay time for a few hundred ms more
redis.delete('name') # Delete the cache again
キャッシュ削除の2回目の失敗はあるのでしょうか?もし2回目の削除に失敗したら、やはりキャッシュとデータベースの間に矛盾が生じることになります。では、どのように修正すればいいのでしょうか?次のオプションを見てみましょう。
先にデータベースを更新し、その後キャッシュを削除します。
外国人が思いついたのは キャッシュ更新方式 キャッシュAsidepatternCache - SidepatternCache - Sidepatternは、記事の言及**アプリケーションは、フェッチが成功した場合、キャッシュからデータを取得する必要がありますし、データベースから直接返す、ない場合は、取得、キャッシュへの成功後、データを更新するには、最初の成功後にデータベースにデータを保存し、キャッシュの有効期限が切れるようにする必要があります。**元のテキストは次のとおりです。
アプリケーションが情報を更新する場合、データストアに変更を加え、キャッシュの対応する項目を無効にすることで、ライトスルー戦略に従うことができます。
次にその項目が必要になったとき、キャッシュ・アサイド戦略を使用すると、更新されたデータがデータストアから取得され、キャッシュに再び追加されることになる。
このソリューションでは、データの不整合は発生しないのでしょうか?例えば、以下のような場合です。
AとBの2つのリクエストがあり、Aはクエリを行い、Bは更新を行うので、次のようなことが起こったとします。
1) キャッシュがちょうど期限切れになった
リクエストAは、データベースにアクセスし、古い値を取得します。
(iii) リクエストBは、新しい値をデータベースに書き込む。
4.書き込み成功後、Bにキャッシュの削除を依頼する
リクエストAはチェックしたメカニズムをキャッシュに書き込み、ダーティデータを発生させる...。
上記を発声すると、確かに不整合なデータが出ますが、XDMはこのようなことが起こる確率を考えてください。仮にこの結果を先に出すとしたら、リクエストBの操作時間が非常に短い、どこまで短いか、つまりリクエストAのデータベースからデータを読み込む操作より、リクエストBのデータベースに書き込む操作の方が速い(redisは非常に速いので、redisの操作時間はとりあえず無視できる)、この場合のみ⑤より先に④が発声できる、しかしデータベースの読み込み操作が書き込み操作よりはるかに速い、そうしないとなぜ読み書きを分離するのか、という条件も必要でしょう。というわけで、このようなことが起こる確率はとてもとても低いのですが、もし強迫性障害の患者さんが登場したら、それを解決しなければならないのでしょうか?あなたは、有効期限を設定するためにキャッシュを使用するか、削除操作の後に読み取り要求が完了することを保証するために遅延二重削除戦略の第二のオプションを使用することができます。
最後の質問
まだ問題があります。つまり、解決策3で発生しうる非常に低い確率のデータ不整合に対する最終的な解決策は、解決策2の遅延ダブル削除戦略ですが、解決策2にも書かれているように、キャッシュ削除に失敗した場合はどうするのでしょうか?やはりデータ不整合の問題になるのでは?最終的にこの問題は、どのようにそれを解決するには?ここでは、再試行のメカニズムを提供するために、再試行の失敗を削除するには、ここで再試行の解決策を提供する。
<ブロッククオート
データベースを更新する
キャッシュの削除に失敗しました。
失敗したキャッシュ削除をメッセージキューに入れる。
ビジネスコードはメッセージキューから削除するキーを取得します。
削除操作が成功するまで試行錯誤を続ける。
概要
今回の記事は、MySQLとRedis間のデータの整合性を確保する方法についてです。MySQLとRedisのデータ整合性については、スクリプトハウスの過去記事を検索していただくか、引き続き以下の関連記事をご覧ください。
関連
-
Navicat for SQLite インストールチュートリアル(インストールキット付き
-
ナビカット15のインストールチュートリアルを超詳しく解説(一番信頼できるのはこれ)
-
JMeterデータベースクエリ操作手順詳細説明
-
SQL実行エンジンを自作する方法
-
Dbeaverを使ったHiveへのリモート接続の詳細方法
-
どのようなデータベースのサブベースのサブテーブルは、どのような状況でサブベースのサブテーブルを使用する必要があります。
-
Navicat Premiumを使用して、データベースのテーブル構造情報をExcelにエクスポートする方法
-
NavicatでMySqlデータベースへの接続が遅い問題
-
SQLリレーショナルモデルの知識まとめ
-
タイプインジェクションとコミットインジェクションのSQLインジェクションチュートリアル
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
DataGripでクリックハウスの時間フィールドが正しく表示されない
-
Djangoプロジェクト最適化データベース運用まとめ
-
Linuxシステム用Navicatアクティベーションチュートリアル
-
DeepinV20 Mariadbのクイックインストールを詳しくご紹介します。
-
SQLyogダウンロード、インストール超詳細チュートリアル(プロテスト永久保存版)
-
Navicat for Mac システムチュートリアルのインストールと使用方法
-
外部キーの関連付けを行う SQL 文の完全な例
-
SQLインジェクションの例とその解決方法
-
navicat トランザクションの自動コミット問題について
-
高額で無料のSQL開発ツール「Beekeeper Studio」解説