キャッシュ透過、キャッシュ雪崩、キャッシュ破壊シーンシミュレーション、ソリューション
cache-best-practice
一、キャッシュスルー、キャッシュ雪崩、キャッシュ破壊シーンシミュレーション
クエリー・メソッド・コード
1、キャッシュスルー
キャッシュスルーとは、存在しないデータをクエリーすることであり、キャッシュ・レイヤとストレージ・レイヤがヒットしないことを意味します.通常は、キャッシュ・レイヤからデータがクエリーされない場合は、キャッシュ・レイヤに書き込まれません.
キャッシュスルーにより、存在しないデータが要求されるたびにストレージ・レイヤにクエリーされ、キャッシュ保護バックエンド・ストレージ・レイヤの意味が失われます.
キャッシュ透過シミュレーション:
データベースにID 1~100のデータが存在し、データベースに存在しないレコードID 101~110を同時に問い合わせる
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ透過.jmx」を開いて要求を実行します.
コンカレント・リクエストを実行すると、クエリー・ログには、すべてのリクエストが毎回データベースに移動していることがわかります.以下はログ・クリップです.
2、キャッシュ雪崩
通常のキャッシュシステム、例えばredis、memcacheなどでは、キャッシュに失効時間を設定しますが、すべてのキャッシュの失効時間が同じであれば、同じ時間に失効すると、すべてのシステムの要求がデータベース層に送信され、dbがこのような大きな圧力に耐えられずシステムがクラッシュする可能性があります.
キャッシュ雪崩シミュレーション:1、ID 1~100を同時に設定キャッシュ .2、1~100のデータを照会し、キャッシュ にヒットする. 3、ID 1~10のキャッシュを手動で削除する、アナログキャッシュが無効になる .4,100同時要求ID 1~10のデータは30回 .
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ雪崩.jmx」を開いて要求を実行
ステップ4を実行すると、クエリー・ログには、大量のリクエストがデータベースに到達し、同じIDで複数のデータベース・クエリーが実行されていることがわかります.ログ・クリップは次のようになります.
3、キャッシュ破壊
期限切れが設定されているkeyの中には、いくつかの時点で超高同時アクセスされる可能性がある場合、非常に「ホットスポット」のデータです.この場合、キャッシュが「破壊」されるという問題を考慮する必要があります.これとキャッシュ雪崩の違いは、ここではあるkeyキャッシュに対して、前者は多くのkeyであることです.キャッシュがある時点で期限切れになったとき、ちょうどこの時点でこのKeyに対して大量の同時要求が来て、これらの要求はキャッシュの期限切れが一般的にバックエンドDBからデータをロードしてキャッシュに戻すことを発見して、この時大同時の要求は瞬時にバックエンドDBを潰す可能性があります.
キャッシュブレークスルーシミュレーション:1、クエリIDが50の要求であると、idが50のデータがキャッシュ にロードされる.2、再照会ID 50の要求、ヒットキャッシュ 3,300同時要求IDが50のデータは、このとき全ヒットキャッシュ を要求する.4、ID 50のキャッシュを手動で削除、アナログキャッシュ失効 .5,300同時要求IDが50のデータは、このとき大量要求がデータベースに向かう、IDが50のキャッシュが に破壊される.
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ破壊.jmx」を開いて要求を実行します.
JMeter同時要求の再実行
手順3を実行すると、クエリー・ログには、リクエストがすべてキャッシュにヒットしたことがわかります.以下はログ・クリップです.
手順5を実行すると、ID 50のリクエストがデータベースに複数回クエリーされ、キャッシュが設定されていることがわかります.その後、キャッシュにヒットしました.以下はログ・クリップです.
二、ベストプラクティス方案テスト
最適化されたクエリー・メソッド・コード
1、キャッシュスルー
テスト計画:スレッド数100、繰り返し1回実行
同時クエリーデータベースに存在しないID 101~110のデータは、各IDが1回だけデータベースクエリーを実行してキャッシュを設定していることがわかります.その後、リクエストがキャッシュにヒットし、キャッシュスルーの問題を効果的に防止します.以下はログクリップです.
ブロンフィルターを入れる
再度jmeterテストを実行すると、IDがブロンフィルタに存在しないことがわかり、直接返されます(ブロンフィルタには確率誤判があるため、IDによっては後のキャッシュやデータベースクエリが実行される場合があります).ログクリップは次のとおりです.
2、キャッシュ雪崩
テスト計画:スレッド数100、30回繰り返し実行
同時要求失効キャッシュIDが1~10のレコードは、各IDがデータベースを1回だけクエリーしてキャッシュを設定し、その後の要求がキャッシュにヒットしていることがわかります
3、キャッシュ破壊
テスト計画:スレッド数100、繰り返し1回
ID 50のキャッシュを無効にする
同時要求失効キャッシュIDが50のレコードには、データベースクエリーを実行してキャッシュを設定した要求が1つしかなく、他の要求がキャッシュにヒットしていることがわかります.ログ・クリップは次のとおりです.
完全なプロジェクトコードリファレンス:cache-best-practiceにjmeterテストスクリプトが含まれています
一、キャッシュスルー、キャッシュ雪崩、キャッシュ破壊シーンシミュレーション
クエリー・メソッド・コード
/**
* 、 、
*
* @param id
* @return
*/
public DataObject getData1(Long id) {
//
DataObject result = getDataFromCache(id);
if (result == null) {
//
result = getDataFromDB(id);
if (result != null) {
//
setDataToCache(id, result);
}
}
return result;
}
1、キャッシュスルー
キャッシュスルーとは、存在しないデータをクエリーすることであり、キャッシュ・レイヤとストレージ・レイヤがヒットしないことを意味します.通常は、キャッシュ・レイヤからデータがクエリーされない場合は、キャッシュ・レイヤに書き込まれません.
キャッシュスルーにより、存在しないデータが要求されるたびにストレージ・レイヤにクエリーされ、キャッシュ保護バックエンド・ストレージ・レイヤの意味が失われます.
キャッシュ透過シミュレーション:
データベースにID 1~100のデータが存在し、データベースに存在しないレコードID 101~110を同時に問い合わせる
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ透過.jmx」を開いて要求を実行します.
コンカレント・リクエストを実行すると、クエリー・ログには、すべてのリクエストが毎回データベースに移動していることがわかります.以下はログ・クリップです.
......
【 】 , id: 110, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 103, DataObject: null
【 】 , id: 103, DataObject: null
【 】 , id: 102, DataObject: null
【 】 , id: 102, DataObject: null
【 】 , id: 108, DataObject: null
【 】 , id: 108, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 103, DataObject: null
【 】 , id: 103, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 102, DataObject: null
【 】 , id: 102, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 109, DataObject: null
【 】 , id: 109, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 110, DataObject: null
......
2、キャッシュ雪崩
通常のキャッシュシステム、例えばredis、memcacheなどでは、キャッシュに失効時間を設定しますが、すべてのキャッシュの失効時間が同じであれば、同じ時間に失効すると、すべてのシステムの要求がデータベース層に送信され、dbがこのような大きな圧力に耐えられずシステムがクラッシュする可能性があります.
キャッシュ雪崩シミュレーション:
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ雪崩.jmx」を開いて要求を実行
ステップ4を実行すると、クエリー・ログには、大量のリクエストがデータベースに到達し、同じIDで複数のデータベース・クエリーが実行されていることがわかります.ログ・クリップは次のようになります.
......
【 】 , id: 1, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 4, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 6, DataObject: null
【 】 , id: 3, DataObject: null
【 】 , id: 7, DataObject: null
【 】 , id: 8, DataObject: null
【 】 , id: 9, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 4, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 6, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 7, DataObject: null
【 】 , id: 6, DataObject: null
【 】 , id: 7, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 9, DataObject: null
【 】 , id: 4, DataObject: null
【 】 , id: 4, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 8, DataObject: null
【 】 , id: 4, DataObject: null
【 】 , id: 8, DataObject: null
【 】 , id: 8, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 3, DataObject: null
【 】 , id: 8, DataObject: null
【 】 , id: 1, DataObject: DataObject(id=1, desc=name:1)
【 】, DataObject: DataObject(id=1, desc=name:1)
【 】 , id: 10, DataObject: null
【 】 , id: 3, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 5, DataObject: null
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】, DataObject: DataObject(id=5, desc=name:5)
【 】, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 7, DataObject: null
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 10, DataObject: null
【 】 , id: 10, DataObject: DataObject(id=10, desc=name:10)
【 】, DataObject: DataObject(id=10, desc=name:10)
......
3、キャッシュ破壊
期限切れが設定されているkeyの中には、いくつかの時点で超高同時アクセスされる可能性がある場合、非常に「ホットスポット」のデータです.この場合、キャッシュが「破壊」されるという問題を考慮する必要があります.これとキャッシュ雪崩の違いは、ここではあるkeyキャッシュに対して、前者は多くのkeyであることです.キャッシュがある時点で期限切れになったとき、ちょうどこの時点でこのKeyに対して大量の同時要求が来て、これらの要求はキャッシュの期限切れが一般的にバックエンドDBからデータをロードしてキャッシュに戻すことを発見して、この時大同時の要求は瞬時にバックエンドDBを潰す可能性があります.
キャッシュブレークスルーシミュレーション:
curl http://127.0.0.1:8080/data/getData1?id=50
curl http://127.0.0.1:8080/data/getData1?id=50
JMeterシミュレーション同時要求を使用して、「シーンシミュレーション-キャッシュ破壊.jmx」を開いて要求を実行します.
curl http://127.0.0.1:8080/data/deleteCache?id=50
JMeter同時要求の再実行
手順3を実行すると、クエリー・ログには、リクエストがすべてキャッシュにヒットしたことがわかります.以下はログ・クリップです.
......
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
, id: 50, DataObject: DataObject(id=50, desc=name:50)
......
手順5を実行すると、ID 50のリクエストがデータベースに複数回クエリーされ、キャッシュが設定されていることがわかります.その後、キャッシュにヒットしました.以下はログ・クリップです.
......
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
......
二、ベストプラクティス方案テスト
最適化されたクエリー・メソッド・コード
public DataObject getData(Long id) {
//
DataObject result = getDataFromCache(id);
if (result == null) {
// , ,
RLock lock = redissonClient.getLock(DATA_LOCK_NAME + id);
lock.lock(15, TimeUnit.SECONDS);
if (lock.isLocked()) {
try {
// , ,
//
result = getDataFromCache(id);
if (result == null) {
//
result = getDataFromDB(id);
//
setDataToCache(id, result);
}
} finally {
//
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
} else {
if (result.getId() == ID_NOT_EXISTS) {
return null;
}
}
return result;
}
1、キャッシュスルー
テスト計画:スレッド数100、繰り返し1回実行
同時クエリーデータベースに存在しないID 101~110のデータは、各IDが1回だけデータベースクエリーを実行してキャッシュを設定していることがわかります.その後、リクエストがキャッシュにヒットし、キャッシュスルーの問題を効果的に防止します.以下はログクリップです.
......
【 】 , id: 110, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 104, DataObject: null
【 】 , id: 109, DataObject: null
【 】 , id: 108, DataObject: null
【 】 , id: 107, DataObject: null
【 】 , id: 102, DataObject: null
【 】 , id: 110, DataObject: null
【 】 , id: 106, DataObject: null
【 】 , id: 101, DataObject: null
【 】 , id: 103, DataObject: null
【 】 , id: 105, DataObject: null
【 】 , id: 109, DataObject: null
【 】, DataObject: null
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: null
【 】, DataObject: null
【 】 , id: 110, DataObject: null
【 】, DataObject: null
【 】 , id: 106, DataObject: null
【 】, DataObject: null
【 】 , id: 107, DataObject: null
【 】, DataObject: null
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: null
【 】, DataObject: null
【 】 , id: 103, DataObject: null
【 】, DataObject: null
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 103, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 103, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 104, DataObject: null
【 】, DataObject: null
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 103, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 108, DataObject: null
【 】, DataObject: null
【 】 , id: 104, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 109, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 103, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 110, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 106, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 104, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 108, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 107, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 105, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 103, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 102, DataObject: DataObject(id=-1, desc=null)
【 】 , id: 101, DataObject: null
【 】, DataObject: null
......
ブロンフィルターを入れる
public DataObject getData(Long id) {
// ,
if (!clusterClient.exists(DATA_BF_NAME, ObjectUtils.nullSafeToString(id))) {
System.out.println(" , id: " + id);
return null;
}
//
DataObject result = getDataFromCache(id);
if (result == null) {
// , ,
RLock lock = redissonClient.getLock(DATA_LOCK_NAME + id);
lock.lock(15, TimeUnit.SECONDS);
if (lock.isLocked()) {
try {
// , ,
//
result = getDataFromCache(id);
if (result == null) {
//
result = getDataFromDB(id);
//
setDataToCache(id, result);
}
} finally {
//
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
} else {
if (result.getId() == ID_NOT_EXISTS) {
return null;
}
}
return result;
}
再度jmeterテストを実行すると、IDがブロンフィルタに存在しないことがわかり、直接返されます(ブロンフィルタには確率誤判があるため、IDによっては後のキャッシュやデータベースクエリが実行される場合があります).ログクリップは次のとおりです.
......
, id: 107
, id: 101
, id: 104
, id: 106
, id: 103
, id: 101
, id: 102
, id: 103
, id: 101
, id: 105
, id: 101
, id: 103
, id: 106
, id: 107
, id: 110
, id: 108
, id: 109
, id: 110
, id: 102
, id: 101
, id: 104
, id: 102
, id: 109
, id: 110
, id: 101
, id: 107
, id: 110
, id: 109
......
2、キャッシュ雪崩
テスト計画:スレッド数100、30回繰り返し実行
同時要求失効キャッシュIDが1~10のレコードは、各IDがデータベースを1回だけクエリーしてキャッシュを設定し、その後の要求がキャッシュにヒットしていることがわかります
【 】 , id: 9, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 7, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 6, DataObject: null
【 】 , id: 3, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 6, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 9, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 10, DataObject: null
【 】 , id: 9, DataObject: null
【 】 , id: 5, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 1, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 6, DataObject: null
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: null
【 】 , id: 7, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 9, DataObject: null
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 10, DataObject: null
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 1, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 2, DataObject: null
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 6, DataObject: null
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 10, DataObject: null
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 1, DataObject: null
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 2, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 6, DataObject: null
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 10, DataObject: null
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 1, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 10, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 2, DataObject: null
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 1, DataObject: DataObject(id=1, desc=name:1)
【 】, DataObject: DataObject(id=1, desc=name:1)
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 10, DataObject: null
【 】 , id: 1, DataObject: null
【 】 , id: 2, DataObject: DataObject(id=2, desc=name:2)
【 】, DataObject: DataObject(id=2, desc=name:2)
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 2, DataObject: null
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 8, DataObject: DataObject(id=8, desc=name:8)
【 】 , id: 9, DataObject: DataObject(id=9, desc=name:9)
【 】 , id: 10, DataObject: DataObject(id=10, desc=name:10)
【 】, DataObject: DataObject(id=10, desc=name:10)
【 】 , id: 10, DataObject: null
【 】 , id: 1, DataObject: DataObject(id=1, desc=name:1)
【 】 , id: 4, DataObject: DataObject(id=4, desc=name:4)
【 】 , id: 5, DataObject: DataObject(id=5, desc=name:5)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
【 】 , id: 2, DataObject: DataObject(id=2, desc=name:2)
【 】 , id: 3, DataObject: DataObject(id=3, desc=name:3)
【 】 , id: 6, DataObject: DataObject(id=6, desc=name:6)
【 】 , id: 7, DataObject: DataObject(id=7, desc=name:7)
3、キャッシュ破壊
テスト計画:スレッド数100、繰り返し1回
ID 50のキャッシュを無効にする
curl http://127.0.0.1:8080/data/deleteCache?id=50
同時要求失効キャッシュIDが50のレコードには、データベースクエリーを実行してキャッシュを設定した要求が1つしかなく、他の要求がキャッシュにヒットしていることがわかります.ログ・クリップは次のとおりです.
......
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: null
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
【 】 , id: 50, DataObject: DataObject(id=50, desc=name:50)
......
完全なプロジェクトコードリファレンス:cache-best-practiceにjmeterテストスクリプトが含まれています