キャッシュスルーとキャッシュ雪崩が分かったので、キャッシュ破壊を理解してください!


キャッシュ破壊とキャッシュ雪崩の違いは、雪崩は多くのkeyに対して行われ、破壊はあるホットスポットkeyに対してのみ行われることである.
キャッシュが期限切れにならないように設定するには、暴力的ですが、ほとんどの問題を解決することができます.もちろん、ほとんどのシーンはあまり適用されません.
ランダムな期限切れを設定すると、このスキームはキャッシュの破壊にはあまり適用されません.破壊はホットスポットkeyに対してのみ行われ、それが失効すると、大量のアクセスがデータベースを破壊します.
残りのシナリオは、例えば、反発ロック、デュアルキャッシュメカニズムを使用しても、キャッシュ破壊の問題を解決することができます.これらのシナリオの具体的な実装を見てみましょう.
キャッシュのプロアクティブ・リフレッシュ
キャッシュは期限切れに設定されており、DBのデータを更新または削除する際にも、キャッシュのデータをアクティブに更新または削除します.
このスキームは容易に理解できるが、実装は複雑であるが、キャッシュを使用する必要があるデータは、デュアルライト・データベースとキャッシュのコードを増やす必要があり、デュアルライト・プロセスでは、データの一貫性を維持する必要がある.
更新の確認
キャッシュは依然として設定の期限切れ時間を維持し、getキャッシュのたびにデータの期限切れ時間と現在の時間と比較し、間隔時間がしきい値より小さい場合、キャッシュをアクティブに更新します.
たとえば(キャッシュの有効期限-現在のシステム時間)が5分未満の場合、キャッシュをリフレッシュし、キャッシュの有効期限をリセットします.
しかし、この方法には致命的な問題があります.データがキャッシュが無効になる5分前に1回のアクセスがなければ、チェック更新はトリガーされず、キャッシュが無効になった後に大量のアクセスが要求されると、キャッシュが破壊されます.
ロックの使用
キャッシュが無効になった後、反発ロックまたはキューによって、リード・データベースとライト・キャッシュのスレッド数を制御します.
第1の方法:全体の方法はsynchronizedで、このようにして大量の要求がDB上に落ちることを防止することができますが、キャッシュが失効していなくても、DBからデータを照会する必要があります.キューに並ぶ必要があります.システムのスループットを低下させることは間違いありません.
public synchronized String getCacheData() {
      String cacheData = "";
      //  Redis
      cacheData = getDataFromRedis();
      if (cacheData.isEmpty()) {
          //    
          cacheData = getDataFromDB();
          //  Redis
          setDataToCache(cacheData);
      }
      return cacheData;
}

第2の方法:キャッシュが無効になった場合、クエリー・データベースの操作のみをロックすることで、キャッシュが無効になっていない場合にも非常に友好的ですが、クエリー・操作ここでロックをかけるのは、他の呼び出しをブロックするだけで、第1の他のスレッドは待たなければなりません.呼び出し側に友好的ではありません.第2のこれらの要求がブロックされた要求は最終的にDBに落ちます.
static Object lock = new Object();

public String getCacheData() {
      String cacheData = "";
      //   Redis
      cacheData = getDataFromRedis();
      if (cacheData.isEmpty()) {
          synchronized (lock) {
              //    
           cacheData = getDataFromDB();
              //  Redis
              setDataToCache(cacheData);
          }
      }
      return cacheData;
 }

3つ目の方法は、反発ロックを使用して、ロックを奪うとデータベースを読み取りキャッシュに書き込み、ロックを奪うことができなければブロックせず、キャッシュを直接読み取り、キャッシュ中にデータが読めない場合(ロックを奪った場合、キャッシュを書き込み成功していない可能性があります)、後で読み取りキャッシュを試してみます.
public String getCacheData(){
   String result = "";
      //  Redis
      result = getDataFromRedis();
      if (result.isEmpty()) {
          if (reenLock.tryLock()) {
              try {
                  //    
                  result = getDataFromDB();
                  //  Redis
                  setDataToCache(result);
              }catch(Exception e){
               //...
              }finally {
                  reenLock.unlock();//   
              }
          } else {
                //  :               :
                //            
              //  Redis
              result = getDataFromRedis();
              if (result.isEmpty()) {
                  try {
                    Thread.sleep(100);
                  } catch (InterruptedException e) {
                  //...
              }
                  return getCacheData();
              }
          }
      }
      return result;
}

デュアルキャッシュ
1つのキャッシュと2つのキャッシュを設定します.1つのキャッシュの有効期限が短く、2つのキャッシュの有効期限が長いか、有効期限が切れていないかを設定します.1つのキャッシュが無効になった後、2つのキャッシュにアクセスし、1つのキャッシュと2つのキャッシュをリフレッシュします.
ダブルキャッシュの方式は、はっきり言って、1級キャッシュと2級キャッシュの中のデータを同時に失効させることができなくて、1級キャッシュが失効した後、複数の要求アクセスがあって、互いに依然として競争ロックで、ロックのスレッドを奪ってデータベースを問合せてキャッシュをリフレッシュして、その他のロックを奪っていないスレッドは、図:
コードを注文するおじさん|文【オリジナル】