分散キャッシュ更新アプリケーション(redis破壊問題)
キャッシュブレークダウン
キャッシュ破壊とは?データベースにデータが存在し、キャッシュデータが何らかの理由で存在しないため、データベースにデータの取得を大量に要求する現象が発生します.この現象は、データベースconnectionsの数が尽き、データベース・サービスが停止する可能性があります.
分散ロックソリューション
要求がデータベースに侵入することを防止し、商品データの照会などの分散ロック方式を用いて実現することができる.
分散ロックスキームの最適化
分散には問題があり、分散ロックの要求を取得できなかった場合、null空のデータが返され、nullデータがカプセル化されるか、whileスリープ方式でキャッシュredisからデータが取得されるのを待つか、以下ではスリープ方式で待つことを例にtry部分コードのみを再構築する.
キャッシュ破壊とは?データベースにデータが存在し、キャッシュデータが何らかの理由で存在しないため、データベースにデータの取得を大量に要求する現象が発生します.この現象は、データベースconnectionsの数が尽き、データベース・サービスが停止する可能性があります.
分散ロックソリューション
要求がデータベースに侵入することを防止し、商品データの照会などの分散ロック方式を用いて実現することができる.
public Product getProductById(Long productId){
log.debug(" id:{}", productId);
//1、
Product product = ehcache.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);
if (product != null){
return product;
}
//2、 redis
product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);
if (product != null){
return product;
}
//3、 db , 【 】
String uuid = UUID.randomUUID().toString();
boolean lockFlag = false;
try {
//
lockFlag = redis.lock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);
if (lockFlag) {
// ,
product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);
if (product != null) {
return product;
}
product = productService.findByProductId(productId);
if (product != null) {
redis.setex(Constants.CACHE_PRODUCT_PREFIX + productId, EXPIRE_TIME, product);
}
}
}catch (Exception e){
log.error(" ", e);
return null; //
}finally {
if (lockFlag){
redis.unlock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);
}
}
return product;
}
分散ロックスキームの最適化
分散には問題があり、分散ロックの要求を取得できなかった場合、null空のデータが返され、nullデータがカプセル化されるか、whileスリープ方式でキャッシュredisからデータが取得されるのを待つか、以下ではスリープ方式で待つことを例にtry部分コードのみを再構築する.
try {
//
lockFlag = redis.lock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);
if (lockFlag) {
// ,
product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);
if (product != null) {
return product;
}
product = productService.findByProductId(productId);
if (product != null) {
redis.setex(Constants.CACHE_PRODUCT_PREFIX + productId, EXPIRE_TIME, product);
}
}else{
long endTime = 0L;
long waitTime = 0L;
while (true) {
// , 200ms
if (waitTime > 200) {
break;
}
// redis
product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);
if (product != null) {
return product ;
} else {
// ,
Thread.sleep(20);
endTime = System.currentTimeMillis();
waitTime = endTime - startTime;
}
}
}catch (Exception e){
log.error(" ", e);
return null; //
}finally {
if (lockFlag){
redis.unlock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);
}
}