キャッシュ ブレークダウンとの違いは、キャッシュ ブレークダウンは、キャッシュには存在しないがデータベースに存在するホット データを指すことです。
例: ホームページ上のホットなニュース、同時アクセス数が非常に多いホットなデータ、キャッシュの有効期限が切れて失敗すると、サーバーは DB にクエリを実行します。このとき、同時アクセス数が多ければ、 DB に対してクエリが実行されると、DB は即座に圧倒される可能性があります。
以下に示すような簡単な図を描きました:
解決策: DB クエリと分散ロック。
問題を解決する前に、まず未処理のコードと動作状況を確認します。
製品 ID に基づいて製品の詳細コードをクエリします
Redis キャッシュをクリアし、同時アクセス テスト用に 5 つのスレッドを開きます。コードは次のとおりです。
DB へのクエリは 1 回だけ行われ、次の 4 つのクエリは Redis キャッシュからフェッチされると予想していましたが、結果はは:
分散ロックはなく、結果は期待通りですが、コンテナは DB に多大な負荷をかけます。
単一サーバーの場合は、Java の同期ロックを直接使用してください。
残念ながら、通常はクライアントがクラスターをデプロイすると、Java の同期ロックは分散ロックを実装できません。
Redis 分散ロックはキャッシュの故障を解決します
Java の組み込みロックは単一のマシンにのみ適用でき、分散することはできません。これは Redis を使用して実現できます。ロック###。
#分散ロックを追加した後のコード//根据ID查询商品
@GetMapping("/{id}")
public R id(@PathVariable String id){
//先查Redis缓存
Object o = redisTemplate.opsForValue().get(id);
if (o != null) {
//命中缓存
System.err.println("id:"+id+",命中redis缓存...");
return R.success(o);
}
//缓存未命中 查询数据库
String lockKey = "lock" + id;
//加锁,10s后过期
for (;;) {
if (redisTemplate.opsForValue().setIfAbsent(lockKey, System.currentTimeMillis(), 10L, TimeUnit.SECONDS)) {
//加锁成功的线程,再次检查
o = redisTemplate.opsForValue().get(id);
if (o != null) {
//命中缓存
System.err.println("Thread:" + Thread.currentThread().getName() + ",id:"+id+",命中redis缓存...");
//释放锁
redisTemplate.delete(lockKey);
return R.success(o);
}
//仍未命中
System.err.println("Thread:" + Thread.currentThread().getName() + ",id:" + id + ",查询DB...");
Goods goods = goodsMapper.selectById(id);
//结果存入Redis
redisTemplate.opsForValue().set(id, goods);
//释放锁
redisTemplate.delete(lockKey);
return R.success(goods);
}
//竞争不到锁,暂时让出CPU资源
Thread.yield();
}
}
以上がRedis 分散ロックがキャッシュの破損を防ぐ方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。