キャッシュ透過、キャッシュ雪崩、キャッシュ破壊シーンシミュレーション、ソリューション

68533 ワード

cache-best-practice
 
一、キャッシュスルー、キャッシュ雪崩、キャッシュ破壊シーンシミュレーション
クエリー・メソッド・コード
    /**
     *     、    、      
     *
     * @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がこのような大きな圧力に耐えられずシステムがクラッシュする可能性があります.
 
キャッシュ雪崩シミュレーション:
  • 1、ID 1~100を同時に設定キャッシュ
  • .
  • 2、1~100のデータを照会し、キャッシュ
  • にヒットする.
  • 3、ID 1~10のキャッシュを手動で削除する、アナログキャッシュが無効になる
  • .
  • 4,100同時要求ID 1~10のデータは30回
  • .
    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を潰す可能性があります.
     
    キャッシュブレークスルーシミュレーション:
  • 1、クエリIDが50の要求であると、idが50のデータがキャッシュ
  • にロードされる.
  • 2、再照会ID 50の要求、ヒットキャッシュ
  • 3,300同時要求IDが50のデータは、このとき全ヒットキャッシュ
  • を要求する.
  • 4、ID 50のキャッシュを手動で削除、アナログキャッシュ失効
  • .
  • 5,300同時要求IDが50のデータは、このとき大量要求がデータベースに向かう、IDが50のキャッシュが
  • に破壊される.
    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テストスクリプトが含まれています