目次
オプション 1: キャッシュの更新、データベースの更新
オプション 2: データベースを更新してキャッシュを更新する
オプション 3: キャッシュを削除してデータベースを更新します
总结
推荐方案
延迟双删
实际场景
写缓存策略
读缓存策略
注意
ホームページ Java &#&チュートリアル Java でキャッシュの一貫性を確保する方法

Java でキャッシュの一貫性を確保する方法

May 02, 2023 pm 01:13 PM
java

オプション 1: キャッシュの更新、データベースの更新

最初にキャッシュが正常に更新されてもデータベースの更新が失敗すると、確実にデータの不整合が発生するため、この方法は簡単に削除できます。

オプション 2: データベースを更新してキャッシュを更新する

このキャッシュ更新戦略は、一般に二重書き込みとして知られています。問題は、データベースを同時に更新するシナリオでは、ダーティ データがキャッシュにフラッシュされました

updateDB();
updateRedis();
ログイン後にコピー

例: 2 つの操作の間の後続のリクエストによってデータベースとキャッシュが変更された場合、この時点でキャッシュを更新すると、データはすでに期限切れになります。

Java でキャッシュの一貫性を確保する方法

オプション 3: キャッシュを削除してデータベースを更新します

問題があります:データベースを更新する前に、クエリ要求の場合、ダーティ データはキャッシュにフラッシュされます

deleteRedis();
updateDB();
ログイン後にコピー

例:2 つの操作の間にデータ クエリが発生すると、古いデータがキャッシュに入れられます。

Java でキャッシュの一貫性を確保する方法

この解決策では、リクエスト データの不一致が発生します。

更新操作のリクエスト A とクエリ操作の別のリクエスト B がある場合。次に、次の状況が発生します。

  • A に書き込み操作の実行とキャッシュの削除を要求します

  • B にクエリを実行して、キャッシュを削除するよう要求します。キャッシュが存在しません

  • B にデータベースにクエリを実行して古い値を取得するように要求します。

  • # B に古い値をキャッシュに書き込むように要求します

  • A に古い値をキャッシュに書き込むよう要求する 新しい値をデータベースに書き込む

##上記の状況では、不整合が発生します。さらに、キャッシュの有効期限戦略を設定しない場合、データは常にダーティ データになります。

オプション 4: データベースを更新してキャッシュを削除します

問題があります:データベースを更新する前にクエリ要求があり、キャッシュが無効です。データベースがクエリされ、キャッシュが更新されます。データベースのクエリとキャッシュの更新の間にデータベースの更新操作が実行された場合、ダーティ データはキャッシュにフラッシュされます

updateDB();
deleteRedis();
ログイン後にコピー

例: データベースとキャッシュの間にクエリがある場合キャッシュ データが更新され、操作中にキャッシュが削除されると、古いデータがキャッシュに置かれます。

Java でキャッシュの一貫性を確保する方法

2 つのリクエストがあり、1 つは A にクエリ操作の実行を要求し、もう 1 つは B に更新操作の実行を要求すると仮定すると、次の状況が発生します。

    キャッシュの有効期限が切れました
  • リクエスト A でデータベースにクエリを実行し、古い値を取得します
  • リクエスト B新しい値をデータベースに書き込む
  • リクエスト B にキャッシュを削除する
  • リクエスト A に見つかった古い値をキャッシュに書き込む
  • #こうなった場合 上記の状況では、確かにダーティデータが発生します。ただし、上記の状況が発生するには先天的な条件があります。つまり、データベース操作の書き込みはデータベース操作の読み取りよりも時間がかかりません。

ただし、データベース読み取り操作の速度ははるかに高速です。書き込み操作よりも

#したがって、この状況は発生しにくくなります。 スキームの比較

スキーム 1 とスキーム 2 の共通の欠点:

データベースの同時更新シナリオでは、ダーティ データがキャッシュされますが、一般に、シナリオが同時に書き込まれる可能性は比較的小さいです。 スレッド セーフティの観点から、ダーティ データが生成されます (例:

スレッド A)データベースを更新しました

  • スレッド B がデータベースを更新しました

  • ##スレッド B がキャッシュを更新しました

  • スレッド B がキャッシュを更新しました

  • #スレッドキャッシュを更新しました
オプション 3 と 4 の共通の欠点:

どちらの順序を採用しても、両方の方法にいくつかの問題があります。 :

    マスター/スレーブの遅延問題: 最初に削除されたか最後に削除されたかに関係なく、データベースのマスター/スレーブの遅延によりダーティ データが生成される可能性があります。
  • キャッシュ削除の失敗: キャッシュの削除に失敗すると、ダーティ データが生成されます。
  • 問題解決のアイデア: 二重削除を遅らせ、以下で紹介する再試行メカニズムを追加します。

キャッシュを更新しますか、それともキャッシュを削除しますか?

    1. キャッシュの更新には一定のメンテナンスコストが必要であり、同時更新では問題が発生します
  • 2. 書き込み読み取りが少ない場合は、読み取り要求がまだ来ておらず、キャッシュが何度も更新されているため、キャッシュの役割を果たしません
  • 3。キャッシュに書き込まれた値が更新されるたびに計算されると、パフォーマンスが無駄になります
キャッシュを削除する利点:

シンプル、低コスト、開発が簡単; 欠点: キャッシュミスの原因キャッシュの更新コストが小さく、読み取りが多く書き込みが少なく、基本的に同時書き込みが存在しない場合は、キャッシュを更新することもできますが、そうでない場合は、キャッシュを削除するのが一般的な方法です。

总结

方案问题问题出现概率推荐程度
更新缓存 -> 更新数据库为了保证数据准确性,数据必须以数据库更新结果为准,所以该方案绝不可行不推荐
更新数据库 -> 更新缓存并发更新数据库场景下,会将脏数据刷到缓存并发写场景,概率一般写请求较多时会出现不一致问题,不推荐使用。
删除缓存 -> 更新数据库更新数据库之前,若有查询请求,会将脏数据刷到缓存并发读场景,概率较大读请求较多时会出现不一致问题,不推荐使用
更新数据库 -> 删除缓存在更新数据库之前有查询请求,并且缓存失效了,会查询数据库,然后更新缓存。如果在查询数据库和更新缓存之间进行了数据库更新的操作,那么就会把脏数据刷到缓存并发读场景&读操作慢于写操作,概率最小读操作比写操作更慢的情况较少,相比于其他方式出错的概率小一些。勉强推荐。

推荐方案

延迟双删

采用更新前后双删除缓存策略

public void write(String key,Object data){
  redis.del(key);
     db.update(data);
     Thread.sleep(1000);
     redis.del(key);
 }
ログイン後にコピー
  • 先淘汰缓存

  • 再写数据库

  • 休眠1秒,再次淘汰缓存

大家应该评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上即可。

这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

问题及解法:

1、同步删除,吞吐量降低如何处理

将第二次删除作为异步的,提交一个延迟的执行任务

2、解决删除失败的方式:

添加重试机制,例如:将删除失败的key,写入消息队列;但对业务耦合有些严重;

Java でキャッシュの一貫性を確保する方法

延时工具可以选择:

最普通的阻塞Thread.currentThread().sleep(1000);

Jdk调度线程池,quartz定时任务,利用jdk自带的delayQueue,netty的HashWheelTimer,Rabbitmq的延时队列,等等

实际场景

我们有个商品中心的场景,是读多写少的服务,并且写数据会发送MQ通知下游拿数据,这样就需要严格保证缓存和数据库的一致性,需要提供高可靠的系统服务能力。

写缓存策略

  • 缓存key设置失效时间

  • 先DB操作,再缓存失效

  • 写操作都标记key(美团中间件)强制走主库

  • 接入美团中间件监听binlog(美团中间件)变化的数据在进行兜底,再删除缓存

Java でキャッシュの一貫性を確保する方法

读缓存策略

  • 先判断是否走主库

  • 如果走主库,则使用标记(美团中间件)查主库

  • 如果不是,则查看缓存中是否有数据

  • 缓存中有数据,则使用缓存数据作为结果

  • 如果没有,则查DB数据,再写数据到缓存

Java でキャッシュの一貫性を確保する方法

注意

关于缓存过期时间的问题

如果缓存设置了过期时间,那么上述的所有不一致情况都只是暂时的。

但是如果没有设置过期时间,那么不一致问题就只能等到下次更新数据时解决。

所以一定要设置缓存过期时间

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

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの平方根 Javaの平方根 Aug 30, 2024 pm 04:26 PM

Java の平方根のガイド。ここでは、Java で平方根がどのように機能するかを、例とそのコード実装をそれぞれ示して説明します。

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

Java の乱数ジェネレーター Java の乱数ジェネレーター Aug 30, 2024 pm 04:27 PM

Java の乱数ジェネレーターのガイド。ここでは、Java の関数について例を挙げて説明し、2 つの異なるジェネレーターについて例を挙げて説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

See all articles