Heim >Datenbank >Redis >So lösen Sie das Redis-Cache-Lawinenproblem

So lösen Sie das Redis-Cache-Lawinenproblem

WBOY
WBOYnach vorne
2023-06-03 09:46:021796Durchsuche

Die Cache-Schicht überträgt eine große Anzahl von Anforderungen und schützt so die Speicherschicht effektiv. Wenn jedoch aufgrund einer großen Anzahl von Cache-Ausfällen eine große Anzahl von Anforderungen auf der Speicherschicht eintrifft oder der gesamte Cache keine Dienste bereitstellen kann, erhöht sich die Belastung der Speicherschicht (eine große Anzahl von Anforderungen fragt die Datenbank ab). Dies ist das Szenario einer Cache-Lawine.

Um die Cache-Lawine zu lösen, können Sie von den folgenden Punkten ausgehen:

1 Halten Sie die Cache-Ebene hoch verfügbar.

Verwenden Sie den Redis-Sentry-Modus oder die Redis-Cluster-Bereitstellungsmethode, d. h. individuell Redis-Knoten gehen offline. Die gesamte Cache-Ebene ist weiterhin verfügbar. Darüber hinaus kann Redis in mehreren Computerräumen bereitgestellt werden, sodass die Cache-Schicht auch bei einem Computerraumabsturz weiterhin hochverfügbar ist.

2. Strombegrenzende und herabstufende Komponenten

Sowohl die Cache-Schicht als auch die Speicherschicht weisen eine Fehlerwahrscheinlichkeit auf und können als Ressourcen betrachtet werden. Da es sich um ein verteiltes System mit hoher Parallelität handelt, kann es, wenn eine Ressource nicht verfügbar ist, zu Ausnahmen kommen, wenn alle Threads diese Ressource erhalten, wodurch das gesamte System nicht verfügbar ist. Ein Downgrade ist in Systemen mit hoher Parallelität ganz normal. Wenn beispielsweise bei Empfehlungsdiensten der personalisierte Empfehlungsdienst nicht verfügbar ist, können Sie ein Downgrade durchführen, um die Hotspot-Daten zu ergänzen, sodass nicht der gesamte Empfehlungsdienst nicht verfügbar ist. Zu den gängigen strombegrenzenden Degradationskomponenten gehören Hystrix, Sentinel usw.

3. Der Cache läuft nicht ab

Die in Redis gespeicherten Schlüssel laufen nie ab, sodass es kein Problem gibt, dass eine große Anzahl von Caches gleichzeitig ausfällt, aber dann benötigt Redis mehr Speicherplatz.

4. Optimieren Sie die Cache-Ablaufzeit

Wählen Sie beim Entwerfen des Caches eine geeignete Ablaufzeit für jeden Schlüssel, um zu vermeiden, dass eine große Anzahl von Schlüsseln gleichzeitig ungültig wird und eine Cache-Lawine verursacht.

5. Verwenden Sie die Mutex-Sperre, um den Cache neu zu erstellen.

Um zu vermeiden, dass eine große Anzahl von Anforderungen gleichzeitig die Speicherebene erreicht, um Daten abzufragen und den Cache neu aufzubauen, können Sie die Mutex-Sperrsteuerung verwenden. B. das Abfragen von Daten auf der Cache-Schicht gemäß dem Schlüssel. Wenn die Cache-Schicht erreicht wird, wird der Schlüssel gesperrt, dann werden die Daten von der Speicherschicht abgefragt, die Daten werden in die Cache-Schicht geschrieben und schließlich wird die Sperre aufgehoben . Wenn andere Threads feststellen, dass das Erlangen der Sperre fehlschlägt, lassen Sie den Thread eine Zeit lang ruhen und versuchen Sie es erneut. Was den Sperrtyp betrifft: Wenn Sie sich in einer eigenständigen Umgebung befinden, können Sie Lock unter dem Java-Concurrent-Paket verwenden. Wenn Sie sich in einer verteilten Umgebung befinden, können Sie die verteilte Sperre (SETNX-Methode in Redis) verwenden.

Cache-Pseudocode für die Mutex-Sperre-Rekonstruktion in einer verteilten Umgebung

/**
 * 互斥锁建立缓存
 *
 **/
public String get(String key) {
   // redis中查询key对应的value
   String value = redis.get(key);
   // 缓存未命中
   if (value == null) {
      // 互斥锁
      String key_mutex_lock = "mutex:lock" + key; 
      // 互斥锁加锁成功
      if(redis.setnx(key_mutex_lock,"1")) { // 返回 0(false),1(true)
          try {
              // 设置互斥锁超时时间,这里设置的是锁的失效时间,而不是key的失效时间
              redis.expire(key_mutex_lock,3*60);
              // 从数据库查询
              value = db.get(key);
              // 数据写入缓存
              redis.set(key,value);
            
          } finally {
               // 释放锁
              boolean keyExist = jedis.exists(key_mutex_lock);
              if(keyExist){
                  redis.delete(key_mutex_lock);
               }
      } else { 
              // 加锁失败,线程休息50ms后重试
               Thread.sleep(50);
               return get(key); // 直接返回缓存结果  
     }
   }
}

Verwendung einer verteilten Redis-Sperre zur Implementierung der Cache-Rekonstruktion in einer verteilten Umgebung. Der Vorteil besteht darin, dass die Designidee einfach ist und die Datenkonsistenz gewährleistet ist , und es kann dazu führen, dass der Benutzer wartet. Gehen Sie davon aus, dass bei hoher Parallelität der Schlüssel während der Cache-Rekonstruktion gesperrt ist. Wenn derzeit 1.000 gleichzeitige Anforderungen vorliegen, werden 999 davon blockiert, was dazu führt, dass 999 Benutzeranforderungen blockiert werden und warten.

6. Asynchrone Cache-Rekonstruktion

Bei diesem Schema wird der Cache mithilfe einer asynchronen Strategie erstellt. Threads werden aus dem Thread-Pool abgerufen, sodass nicht alle Anforderungen direkt die Speicherschicht erreichen Dieses Schema bedeutet eine logische Zeitüberschreitung bei der Schlüsselwartung. Wenn die logische Zeitüberschreitung unter der aktuellen Zeit liegt, bedeutet dies, dass der aktuelle Cache abgelaufen ist und der Cache aktualisiert werden sollte wird direkt zurückgegeben. In Redis ist beispielsweise die Ablaufzeit des Schlüssels auf 60 Minuten und die logische Ablaufzeit im entsprechenden Wert auf 30 Minuten festgelegt. Auf diese Weise kann der Cache dieses Schlüssels asynchron aktualisiert werden, wenn der Schlüssel die logische Ablaufzeit von 30 Minuten erreicht. Während des Aktualisierungszeitraums des Caches ist der alte Cache jedoch weiterhin verfügbar. Diese asynchrone Cache-Rekonstruktionsmethode kann wirksam verhindern, dass eine große Anzahl von Schlüsseln gleichzeitig ungültig wird.

/**
  *  异步重建缓存: ValueObject为对应的封装的实体模型
  *
  **/
public String get(String key) {
    // 重缓存中查询key对应的ValueObject对象
    ValueObject valueObject = redis.get(key);
    // 获取存储中对应的value值
    String value = valueObject.getValue();
    // 获取实体模型中的缓存过期的时间:timeOut = 设置缓存时的当前时间+过期时间(如30秒,60秒等等)
    long logicTimeOut = valueObject.getTimeOut();  // 等位换算为long类型
    // 当前可以在逻辑上失效
    if (logicTimeOut <= System.currentTimeMillis()) {
         // 异步更新缓存
         threadPool.execute(new Runnable() {
             String key_mutex_lock = "mutex_lock" + key;
              // 互斥锁加锁成功
      if(redis.setnx(key_mutex_lock,"1")) { // 返回 0(false),1(true)
          try {
              // 设置互斥锁超时时间,这里设置的是锁的失效时间,而不是key的失效时间
              redis.expire(key_mutex_lock,3*60);
              // 从数据库查询
              dbValue = db.get(key);
              // 数据写入缓存
              redis.set(key,dbValue);
            
          } finally {
              // 释放锁
              boolean keyExist = jedis.exists(key_mutex_lock);
              if(keyExist){
                  redis.delete(key_mutex_lock);
               }
             
         }
      } else { 
             
              
             }
             
         
         });
       return value; // 直接返回缓存结果  
    }
}

Das obige ist der detaillierte Inhalt vonSo lösen Sie das Redis-Cache-Lawinenproblem. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen