目次
オプション 1: 空のオブジェクト キャッシュまたはデフォルト値
解決策 2: 相互に排他的な排他ロックを使用して故障を防止する
キャッシュの侵入
意味
レコードのクエリをリクエストするとき、最初に redis でクエリを実行し、次に mysql でクエリを実行すると、レコードが見つからないことがわかりますが、リクエストは毎回データベースにヒットするため、バックグラウンド データベースへの負荷が大幅に増加します。は「ペネトレーション」のようなもので、あたかもキャッシュされているかのようにデータベースに直接アクセスします。この現象はキャッシュペネトレーションと呼ばれます。この現象はキャッシュペネトレーションと呼ばれ、このredisは装飾になります。
Web サイトを悪意を持って攻撃する場合、存在しない ID を使用してデータをクエリすると、データベースに対して大量のリクエストが生成されます。過剰な圧力によりデータベースがクラッシュする可能性があります。
解決
オプション 1: 空のオブジェクト キャッシュまたはデフォルト値
キャッシュの侵入が発生すると、クエリされたデータに対して Null 値または Redis のビジネス レイヤーとネゴシエートされたデフォルト値をキャッシュできます (たとえば、インベントリのデフォルト値を 0 に設定できます)。その直後、アプリケーションによって送信された後続のリクエストがクエリされると、Null 値またはデフォルト値を Redis から直接読み取ってビジネス アプリケーションに返すことができるため、処理のためにデータベースに大量のリクエストを送信する必要がなく、維持することができます。データベースの通常の動作。
Redis がデータを見つけられず、データベースもデータを見つけることができない場合は、キーの値を Redis に保存し、 value="null" を設定します。次回このキーを使用してクエリを実行するときに、データベースに再度クエリを実行する必要はありません。この処理方法には確かに問題があり、渡される存在しない Key 値が毎回ランダムであれば、それを Redis に保存する意味がありません。そして、キャッシュされる夏休みが増えるにつれて、Redis に対するプレッシャーが増大し、キャッシュされたキーにはプレッシャーを共有するための有効期限が設定される可能性があります。
オプション 2: ブルーム フィルター
- 既存のデータのキーをブルーム フィルターに保存することは、Redis の前でブルーム フィルターをブロックすることと同じです。
- 新しいリクエストがある場合は、まずそれがブルーム フィルターに存在するかどうかを確認します。
- データがブルーム フィルターに存在しない場合は、直接返されます。
- ブルーム フィルターが既に存在する場合は、キャッシュされた Redis をクエリし、Redis に見つからない場合は、MySQL データベースを再度クエリします。
ブルーム フィルターは 1970 年にブルームによって提案されました。これは実際には長いバイナリ ベクトルと一連のランダム マッピング関数です。ブルーム フィルターを使用すると、要素がコレクション内にあるかどうかを取得できます。
一言で言えば、初期値がゼロのビット配列と、セット内に要素が存在するかどうかを迅速に判断するために使用される複数のハッシュ関数で構成されます。
キャッシュの内訳
意味
多数のリクエストが同時にキーをクエリし、そのときにたまたまそのキーが無効だった場合、多数のリクエストがデータベースにヒットします (簡単に言えば、ホットスポット キーが突然無効になり、mysql が無効になります)激しく殴る)。
キャッシュが壊れる主な理由は、キャッシュ内のデータに有効期限を設定していることです。あるタイミングでデータベースから大量のデータを取得し、同じ有効期限を設定すると、キャッシュされたデータも同時に期限切れになり、キャッシュの破綻が発生します。
- 時間が来れば自然に片づけられましたが、それでも訪れていました。
- キーを削除したところ、突然アクセスされてしまいました。
解決
解決策 1: ホットスポット データの有効期限が切れない
ホットスポット データの場合、企業が許可している場合は、有効期限のないキーをホットスポット キーに設定できます。
解決策 2: 相互に排他的な排他ロックを使用して故障を防止する
分散ロックの考え方を使用すると、キーごとに、同時に 1 つのスレッドだけがバックエンド サービスにクエリを実行することが保証されます。特定のスレッドがバックエンド サービスにクエリを実行している間、他のスレッドにはアクセス許可がありません。分散ロックを取得して待機する必要があります。クエリの後、Redis に Write を返し、他のリクエスト スレッドは Redis でクエリを実行します。当然、これによりシステムのパフォーマンスが低下します。
サンプル Java コードは次のとおりです。
public User findUserById2(Integer id) {
User user = null;
String key = CACHE_KEY_USER+id;
//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql
user = (User) redisTemplate.opsForValue().get(key);
if(user == null) {
//2 大厂用,对于高QPS的优化,进来就先加锁,保证一个请求操作,让外面的redis等待一下,避免击穿mysql
synchronized (UserService.class){
user = (User) redisTemplate.opsForValue().get(key);
//3 二次查redis还是null,可以去查mysql了(mysql默认有数据)
if (user == null) {
//4 查询mysql拿数据
user = userMapper.selectByPrimaryKey(id);//mysql有数据默认
if (user == null) {
return null;
}else{
//5 mysql里面有数据的,需要回写redis,完成数据一致性的同步工作
//setnx 不存在才创建
redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS);
}
}
}
}
return user;
}
キャッシュ雪崩
意味
キャッシュ雪崩とは、キャッシュされたデータの大規模なバッチと大量のクエリ データの有効期限を指し、データベースに過剰な負荷がかかり、ダウンタイムさえも引き起こします。キャッシュ ブレークダウンとは異なり、キャッシュ ブレークダウンは、同じデータの同時クエリを指します。キャッシュ アバランシェとは、別のデータの有効期限が切れ、多くのデータが見つからないため、データベースがチェックされることを意味します。別の状況では、Redis ホストがハングし、 Redis が完全にクラッシュします。
ある時点で、中央のキャッシュに障害が発生するか、キャッシュ システムに障害が発生し、すべての同時トラフィックがデータベースに直接到達します。データ ストレージ層への呼び出し数は劇的に増加し、データベースが大量のトラフィックで圧倒されるまでに時間はかかりません。
解決
オプション 1: 有効期限をランダムに設定する
元の失敗時間にランダムな値 (1 ~ 5 分など) をランダムに追加します。これにより、同じ有効期限を使用することによって引き起こされるキャッシュ雪崩が回避されます。
オプション 2: キャッシュのウォームアップ
キャッシュプリヒートとは、あらかじめキャッシュにデータを追加しておき、データに変更があった場合には最新のデータをキャッシュに更新することです。
オプション 3: Redis クラスター
Redis のダウンタイムによって引き起こされるキャッシュ雪崩を防ぐために、Redis クラスターを構築して Redis の耐災害性を向上させることができます。