キャッシュ雪崩
その理由の雪崩は1.1キャッシュを生成しました
キャッシュ雪崩人気の理解は簡単です:オリジナルのキャッシュミスはまだデータベースに照会することになっている(キャッシュは通常、下図にRedisのから入手)新しいキャッシュ中にキャッシュへのアクセスのためのすべての要求に達していない、(またはデータがキャッシュにロードされていない)ので、CPUおよびメモリ・データベース上の巨大な圧力ながら、データベースには、システムの崩壊をもたらし、深刻なダウンタイムを引き起こす可能性があります。
キャッシュの無効化時間
1.2ソリューション
雪崩効果基盤となるシステム上のキャッシュ無効化の影響は非常に怖いです!それがこの問題を解決するための任意の方法はありますか?次のように基本的なソリューションは、以下のとおりです。
- 分散ロック:ほとんどのシステム設計者はいても、それが一定にすることができ、読み、一回の書き込みをするデータベースのための多数のスレッドが、データベースキャッシュの無効化にあまりにも多くの圧力を避けるためにことを保証する方法がないことを保証するために、ロックやキューを考えます同時に、データベース上の圧力を緩和するだけでなく、システムの程度のスループットを低下させます。
- メッセージングミドルウェアを使用します
- そして、二次キャッシュ(Redisの+ Ehcacheの)
- 同じように、ユーザーの行動の主要な故障時間解析Redisの割り当てられた共有、時間のキャッシュの無効化が均等に分散させるようにしてください。
- キャッシュサーバがダウンしているので、それがある場合は、次のような考慮する用意ショット、呼び出すことができます。Redisのスタンバイを、しかし、更新トランザクションに関連するダブルバッファリングの問題は、更新がダーティデータを読むかもしれない、あなたが解決するために取る必要があります。
1.3ロックモード
- データベースサーバへのリクエストが多数データベースサービス要求を制限することを突然、学校崩壊の影響を解決するための分散ロック(ローカルロック)を使用します。私たちは、そうでない状況が直接キューイングされ、データベースにアクセスするためにその一つだけのスレッド(要求)動作を保証するために、このメカニズムのロックを使用することができます。(クラスタサーバは、その後、あなたが分散ロックを使用する必要がある場合は、このロックは、スタンドアローン版を使用することができます)、サービスは確かにアバランシェ効果を解決することができますが、サーバーの問題のスループットが低下します。(小規模プロジェクトに適しました)
- キャッシュミスした後、スレッドやキュー・データベースの数を制御するためにロックすることにより、書き込みキャッシュをお読みください。例えば、1つのスレッドのみのデータと書き込みキャッシュを照会することを可能にするためのキー、他のスレッドが待機します。
@RequestMapping("/getUsers")
public Users getByUsers(Long id) {
// 1.先查询redis
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
String userJson = redisService.getString(key);
if (!StringUtils.isEmpty(userJson)) {
Users users = JSONObject.parseObject(userJson, Users.class);
return users;
}
Users user = null;
try {
lock.lock();
// 查询db
user = userMapper.getUser(id);
redisService.setSet(key, JSONObject.toJSONString(user));
} catch (Exception e) {
} finally {
lock.unlock(); // 释放锁
}
return user;
}
- 注意:キューをロックするだけで、データベースへの圧力を軽減するために、システムのスループットを改善しません。再建中の高い同時、キーバッファと仮定すると、ロックされた999がブロックされている1000以上の要求であるました。また、ユーザーはタイムアウトを待つことになります、これは緩和的なアプローチです。
1.4メッセージングミドルウェア
1.5プライマリおよびセカンダリキャッシュ
A1は、A2、A1キャッシュの有効期限が設定されている短期へのアクセスに失敗した場合、二次キャッシュを行い、元のA1をキャッシュし、A2のコピーが、キャッシュされ、A2は、長期的に設定されている(この点がサプリメントです)
1.6共有配分しRedisのキー有効期限
異なるキーとしても、可能な限りキャッシュミスの時点に異なる有効期限の時間を設定します。同じ時刻に設定Redisのデータは、失敗しません
第二に、キャッシュの浸透
- キャッシュの浸透がないデータベースで、ユーザーのクエリデータを参照し、自然にキャッシュ内には存在しません。これは、キャッシュ内に見つからない場合は、ユーザーのクエリに再び再照会し、データベースへのたびになり、その後、空に戻ります。このような要求は、多くの場合、キャッシュヒット率が言及されているキャッシュダイレクトアクセスデータベースを、バイパスします。
- 解決策はこれです:あなたは、データベースキャッシュに保存されている空の直接設定されたデフォルト値なので、バッファに値がある得るために二度目に照会が、データベースへのアクセスを継続しない場合、このアプローチは、最もシンプルで、粗です。
- nullの結果が、また、キャッシュされるので、キャッシュが空のクエリの場合に回避することができ、同じ要求が直接空返すことができ、次回は、とき浸透を引き起こしました。また、鍵事前チェックで照会し、null値を格納するために独立したキャッシュ領域を提供され、その後、後ろの通常のキャッシュロジックにリリース。
private String SIGN_KEY = "${NULL}";
public String getByUsers2(Long id) {
// 1.先查询redis
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
String userName = redisService.getString(key);
if (!StringUtils.isEmpty(userName)) {
return userName;
}
System.out.println("######开始发送数据库DB请求########");
Users user = userMapper.getUser(id);
String value = null;
if (user == null) {
// 标识为null
value = SIGN_KEY;
} else {
value = user.getName();
}
redisService.setString(key, value);
return value;
}
- nullの結果が、また、キャッシュされるので、キャッシュが空のクエリの場合に回避することができ、同じ要求が直接空返すことができ、次回は、とき浸透を引き起こしました。また、鍵事前チェックで照会し、null値を格納するために独立したキャッシュ領域を提供され、その後、後ろの通常のキャッシュロジックにリリース。
- 注意:保存されているIPの真の値が対応する空の前にキャッシュをクリアするために対応する必要性を与えた場合。
ホットキー
ホットキー:非常に多くの場合、キーの訪問、キー障害が増加した負荷、システムがクラッシュし、その結果、キャッシュを構築するためのスレッドを見てきました。ソリューション:
- 分散ロックが配布などロック、同期のシングルユース、ロックを使用してください。
- キャッシュの有効期限が設定されますが、対応する値のキーにされていません。検出された有効期限の非同期よりも長く保存されている場合は、キャッシュを更新します。
- 期限切れ満了時間値t1 t0の小満了時間t1よりも設定値で、拡張し、更新キャッシュ動作T1を行います。