Redis Kapitel 5 und 6 – Redis Concurrent Cache-Architektur und Leistungsoptimierung

1. Cache-Design

1. Cache-Penetration

Cache-Penetration bezieht sich auf das Abfragen von Daten, die überhaupt nicht vorhanden sind und weder auf die Cache-Schicht noch auf die Speicherschicht treffen. Wenn die Daten aus Gründen der Fehlertoleranz nicht in der Speicherschicht gefunden werden können, werden sie normalerweise nicht beschrieben die Cache-Schicht.
Durch die Cache-Penetration werden jedes Mal nicht vorhandene Daten auf der Speicherebene abgefragt, wodurch die Bedeutung des Cache-Schutz-Back-End-Speichers verloren geht.

Es gibt zwei grundlegende Gründe für das Eindringen in den Cache:
Erstens liegt ein Problem mit dem eigenen Geschäftscode oder den eigenen Geschäftsdaten vor.
Zweitens verursachen einige böswillige Angriffe, Crawler usw. eine große Anzahl leerer Treffer.

Lösung für das Problem der Cache-Penetration:
(1) Leere Objekte zwischenspeichern und eine Ablaufzeit für diesen Cache festlegen.
Fügen Sie hier eine Bildbeschreibung ein
(2) Der Bloom-Filter
kann auch verwendet werden. Der Bloom-Filter führt zuerst einen Filter durch, und der Bloom-Filter kann im Allgemeinen nicht vorhandene Daten herausfiltern. Verhindern, dass die Anfrage an das Backend gesendet wird. Wenn ein Bloom-Filter angibt, dass ein Wert vorhanden ist, ist dies wahrscheinlich nicht der Fall; wenn er sagt, dass dies nicht der Fall ist, ist dies mit Sicherheit nicht der Fall.
Fügen Sie hier eine Bildbeschreibung ein
Ein Bloom-Filter ist einfach ein großes Bit-Array und mehrere verschiedene unvoreingenommene Hash-Funktionen. Die sogenannte Unvoreingenommenheit bedeutet, dass der Hashwert des Elements relativ einheitlich berechnet werden kann.
Beim Hinzufügen eines Schlüssels zum Bloom-Filter werden mehrere Hash-Funktionen verwendet, um den Schlüssel zu hashen, um einen ganzzahligen Indexwert zu erhalten, und dann wird eine Modulo-Operation für die Länge des Bit-Arrays ausgeführt, um eine Position zu erhalten. Jede Hash-Funktion berechnet a andere Position. Setzen Sie dann diese Positionen des Bit-Arrays auf 1, um den Additionsvorgang abzuschließen.
Wenn der Bloom-Filter wie add fragt, ob der Schlüssel existiert, berechnet er auch mehrere Positionen des Hashs, um zu sehen, ob diese Positionen im Bitarray alle 1 sind. Solange ein Bit 0 ist, bedeutet dies, dass dieser Schlüssel nicht existiert im Blütenfilter. Wenn sie alle 1 sind, bedeutet dies nicht, dass der Schlüssel vorhanden sein muss, aber es ist sehr wahrscheinlich, dass er existiert, da diese Bits auf 1 gesetzt sind, was durch die Existenz anderer Schlüssel verursacht werden kann. Wenn das Bit-Array relativ spärlich ist, ist die Wahrscheinlichkeit hoch, und wenn das Bit-Array überfüllt ist, nimmt die Wahrscheinlichkeit ab.
Diese Methode eignet sich für Anwendungsszenarien, in denen die Datentrefferrate nicht hoch ist, die Daten relativ fest sind und die Echtzeitleistung gering ist (normalerweise ist der Datensatz groß). Die Codepflege ist relativ kompliziert, aber der Cache-Speicherplatz ist relativ kompliziert ist sehr klein.
Fügen Sie hier eine Bildbeschreibung ein
Der Kerncode lautet wie oben: Erstellen Sie zunächst einen Bloom-Filter über Redisson, geben Sie ihm einen Namen. Das Wichtigste ist, die Größe des Filters festzulegen. Dies hängt tatsächlich vom Geschäftsszenario ab, davon, wie viele Daten Ihr Redis zwischenspeichern muss Legen Sie dann eine Fehlerrate fest, da der Bloom-Filter nicht vorhandene Schlüssel nicht perfekt herausfiltern kann.
Speichern Sie dann den zwischenzuspeichernden Datenschlüssel im Bloom-Filter. Dies entspricht der Beurteilung, ob das Element in der Sammlung vorhanden ist!
Hinweis: Um einen Bloom-Filter zu verwenden, müssen Sie alle Daten im Voraus in den Bloom-Filter einfügen und beim Hinzufügen von Daten in den Bloom-Filter einfügen. Der Bloom-Filter kann keine Daten löschen. Wenn Sie sie löschen möchten, müssen Sie dies
tun Daten neu initialisieren.

(2.) Cache-Fehler (Zusammenbruch)
Aufgrund einer großen Anzahl von Caches oder des gleichzeitigen Ausfalls desselben Caches kann eine große Anzahl von Anforderungen gleichzeitig in den Cache eindringen und direkt an die Datenbank gelangen, was möglicherweise zu Problemen führt Dies führt zu übermäßigem Druck auf die Datenbank oder sogar zum Aufhängen. In dieser Situation ist es am besten, die Cache-Ablaufzeit dieses Datenstapels innerhalb eines bestimmten Zeitraums auf unterschiedliche Zeiten festzulegen.
Fügen Sie hier eine Bildbeschreibung ein
Für die Cache-Aufschlüsselung gibt es im Allgemeinen zwei Lösungen:
Die erste besteht darin, eine zufällige Ablaufzeit für eine große Anzahl von Caches festzulegen, damit diese Schlüssel nicht sofort ablaufen. Die zweite besteht darin,
verteilte Sperren hinzuzufügen, wenn ein Thread die Sperre erhält Um die Daten abzurufen, werden die Daten in Redis zwischengespeichert, und die restlichen Threads gehen zu Redis, um sie abzurufen

(3) Cache-Lawine
Da die Cache-Schicht eine große Anzahl von Anforderungen überträgt, schützt sie die Speicherschicht wirksam. Wenn die Cache-Schicht jedoch aus bestimmten Gründen keine Dienste bereitstellen kann (z. B. kann die Cache-Schicht keine große Parallelität unterstützen oder ... Das Cache-Design ist nicht gut. Ähnlich wie bei einer großen Anzahl von Zugriffsanforderungen auf Bigkey, was zu einem starken Rückgang der vom Cache unterstützten Parallelität führt. Daher trifft eine große Anzahl von Anforderungen auf die Speicherschicht und die Anzahl der Aufrufe zur Speicherschicht wird stark ansteigen, was dazu führt, dass die Speicherschicht kaskadiert.

Um das Cache-Lawinenproblem zu verhindern und zu lösen, können wir von den folgenden drei Aspekten ausgehen.
1) Stellen Sie eine hohe Verfügbarkeit von Cache-Layer-Diensten sicher, z. B. mithilfe von Redis Sentinel oder Redis Cluster.
2) Abhängige Isolationskomponenten verschmelzen und verschlechtern sich für den Back-End-Strombegrenzer. Verwenden Sie beispielsweise Sentinel- oder Hystrix-Strombegrenzungs- und Downgrade-Komponenten.
Beispielsweise können wir aufgrund der Verschlechterung des Dienstes unterschiedliche Verarbeitungsmethoden für unterschiedliche Daten anwenden. Wenn die Geschäftsanwendung auf nicht zum Kerngeschäft gehörende Daten (z. B. E-Commerce-Produktattribute, Benutzerinformationen usw.) zugreift, wird die Abfrage dieser Daten aus dem Cache vorübergehend gestoppt, sondern die vordefinierten Standardverschlechterungsinformationen, Nullwerte oder Fehlermeldungen werden direkt zurückgegeben Wenn die Geschäftsanwendung auf Kerndaten (z. B. E-Commerce-Produktinventar) zugreift, ist es ihr weiterhin gestattet, den Cache abzufragen, und wenn der Cache fehlt, kann sie weiterhin die Datenbank durchlesen.
3) Proben Sie im Voraus. Bevor das Projekt online geht, werden nach dem Ausfall der Caching-Ebene die Anwendungs- und Back-End-Lastbedingungen sowie mögliche Probleme geprobt und auf dieser Grundlage einige Vorplanungseinstellungen vorgenommen.

2. Optimierung der Hotspot-Cache-Schlüsselrekonstruktion

Entwickler verwenden die Strategie „Caching + Ablaufzeit“, um das Lesen und Schreiben von Daten zu beschleunigen und regelmäßige Datenaktualisierungen sicherzustellen. Dieser Modus kann grundsätzlich die meisten Anforderungen erfüllen.
Wenn jedoch zwei Probleme gleichzeitig auftreten, kann dies zu schwerwiegenden Schäden an der Anwendung führen:

  • Der aktuelle Schlüssel ist ein Hotkey (z. B. eine beliebte Unterhaltungsnachricht oder ein Produkt mit einem plötzlichen Anstieg der Besuche, z. B. Banlangen während der Epidemie), und die Parallelität ist sehr groß
  • Die Wiederherstellung des Caches kann nicht in kurzer Zeit abgeschlossen werden, da es sich möglicherweise um eine komplexe Berechnung handelt, z. B. komplexes SQL, mehrere E/A, mehrere Abhängigkeiten usw.

In dem Moment, in dem der Cache ungültig wird, gibt es eine große Anzahl von Threads, um den Cache neu zu erstellen, was die Belastung des Backends erhöht und sogar zum Absturz der Anwendung führen kann.
Die Hauptlösung dieses Problems besteht darin, zu vermeiden, dass eine große Anzahl von Threads gleichzeitig den Cache neu aufbaut. Wir können einen Mutex ( Lese-/Schreibsperre
) verwenden , um das Problem zu lösen. Mit dieser Methode kann nur ein Thread den Cache neu erstellen, während andere Threads darauf warten, dass der Thread, der den Cache neu aufbaut, die Ausführung beendet, und dann die Daten aus dem Cache abrufen nochmal.

3. Inkonsistenz zwischen Cache- und Datenbankdaten

  1. Doppelte Schreibinkonsistenz

Fügen Sie hier eine Bildbeschreibung ein
Erläuterung: Wenn Thread 1 die Datenbank aktualisiert, wurde der Cache aus verschiedenen Gründen wie Netzwerk oder Geschäftslogik nicht aktualisiert. Zu diesem Zeitpunkt aktualisiert Thread 2 auch diese Daten und aktualisiert den Cache. Schließlich aktualisiert Thread 1 den Cache. Dann Es kommt zu Dateninkonsistenzen

  1. Interpretation von Inkonsistenzen bei der Lese- und Schreibparallelität
    Fügen Sie hier eine Bildbeschreibung ein
    : Wenn Thread 1 gleichzeitig die Daten aktualisiert und den Cache löscht, fragt Thread 3 den Cache ab und stellt fest, dass keine Daten vorhanden sind, da Thread 1 den Cache gelöscht hat. Anschließend führt Thread 3 eine Überprüfung durch die Datenbank und möchte gleichzeitig den Cache aktualisieren, aber aus verschiedenen Gründen wie Netzwerkschwankungen, Geschäftslogik usw. blieb er hängen. Zu diesem Zeitpunkt aktualisierte Thread 2 diese Daten und löschte gleichzeitig den Cache , aber Thread 3 hat die alten Daten trotzdem im Cache aktualisiert.

Lösung:
1. Bei Daten mit geringer Parallelitätswahrscheinlichkeit (z. B. Bestelldaten in der persönlichen Dimension, Benutzerdaten usw.) ist dieses Problem kaum zu berücksichtigen, und Cache-Inkonsistenzen treten selten auf. Sie können eine Ablaufzeit hinzufügen die zwischengespeicherten Daten. Es reicht aus, von Zeit zu Zeit die aktive Aktualisierung des Lesevorgangs auszulösen.
2. Selbst wenn die Parallelität hoch ist und das Unternehmen kurzfristige Inkonsistenzen zwischen Cache-Daten (z. B. Produktnamen, Produktklassifizierungsmenüs usw.) tolerieren kann, können Caching plus Ablaufzeit die meisten Business-Caching-Anforderungen dennoch lösen.
3. Wenn Sie die Inkonsistenz der zwischengespeicherten Daten nicht tolerieren können, können Sie verteilte Lese-/Schreibsperren hinzufügen, um sicherzustellen, dass gleichzeitige Lese- und Schreibvorgänge oder Schreibvorgänge in der richtigen Reihenfolge in die Warteschlange gestellt werden und Lese- und Lesevorgänge keiner Sperre entsprechen.
4. Sie können auch den Open-Source-Kanal von Ali verwenden, um den Cache zeitnah zu ändern, indem Sie die Binlog-Protokolle der Datenbank überwachen. Die Einführung neuer Middleware erhöht jedoch die Komplexität des Systems.
Zusammenfassen:

  • Der Zweck der Einführung von Caching besteht darin, die Leistung zu verbessern. Die oben genannten Lösungen gelten auch für mehr Lesevorgänge und weniger Schreibvorgänge. Wenn eine Situation mit mehr Lesevorgängen und mehr Schreibvorgängen vorliegt und die Inkonsistenz des Caches nicht empfangen werden kann, liegt keine vor Du musst den Cache überhaupt nutzen. Das reicht nicht. Bist du stark genug?
  • Wenn die Datenbank dem Druck nicht standhalten kann, kann der Cache natürlich auch als Hauptspeicher zum Lesen und Schreiben von Daten verwendet werden. Die Daten werden asynchron mit der Datenbank synchronisiert und die Datenbank dient nur als Datensicherung.
  • Bei den im Cache abgelegten Daten sollte es sich um Daten handeln, die keine hohe Echtzeitleistung und -konsistenz erfordern. Denken Sie daran, nicht zu viel zu entwerfen und zu kontrollieren, um den Cache zu nutzen und gleichzeitig absolute Konsistenz zu gewährleisten, was die Komplexität des Systems erhöhen würde!

4. Große Gefahren!

In Redis kann eine Zeichenfolge bis zu 512 MB groß sein, und eine sekundäre Datenstruktur (wie Hash, Liste, Set, Zset) kann etwa 4 Milliarden (2 ^ 32-1) Elemente speichern, in der Praxis treten jedoch die folgenden zwei Situationen auf , ich denke, es ist Bigkey.

  1. String-Typ: Seine Größe spiegelt sich darin wider, dass ein einzelner Wert sehr groß ist, und es wird allgemein davon ausgegangen, dass ein Bigkey 10 KB überschreitet.
  2. Nicht-String-Typen: Hashes, Listen, Mengen und geordnete Mengen. Ihre Größe spiegelt sich in der großen Anzahl von Elementen wider.
    Im Allgemeinen wird der Zeichenfolgentyp innerhalb von 10 KB gesteuert und die Anzahl der Hash-, Listen-, Set- und Zset-Elemente sollte 5000 nicht überschreiten.

Verwenden Sie für Bigkeys, die keine Zeichenfolgen sind, nicht del zum Löschen, verwenden Sie hscan, sscan, zscan zum schrittweisen Löschen und achten Sie gleichzeitig darauf, das automatische Löschen der Bigkey-Ablaufzeit zu verhindern (z. B. wenn ein 2-Millionen-Zset festgelegt ist). in 1 Stunde ablaufen, wird der Del-Vorgang ausgelöst, was zu einer Blockierung führt)

Die Gefahren von Bigkey:

  • 1. Redis blockieren

  • 2. Netzwerküberlastung
    Bigkey bedeutet, dass der zu generierende Netzwerkverkehr jedes Mal groß ist. Angenommen, ein Bigkey ist 1 MB groß und das Clientzugriffsvolumen beträgt 1000 pro Sekunde, dann werden 1000 MB Datenverkehr pro Sekunde generiert. Für normale Gigabit-Netzwerkkarten ( Laut Aufgrund der Bytezahl (128 MB/s) ist dies eine Katastrophe für einen Server, und der allgemeine Server wird in einem Einzelmaschinen-Mehrinstanzmodus bereitgestellt, was bedeutet, dass ein Bigkey auch andere Instanzen beeinflussen kann, und die Konsequenzen sind unvorstellbar.

  • 3. Es gibt einen großen Schlüssel zum Löschen überfälliger Daten
    , der sicher und zuverlässig ist (nur einfache Befehle wie hget, lpop, zscore usw. ausführt), aber eine Ablaufzeit festlegt. Wenn er abläuft, wird er gelöscht. Wenn Der asynchrone Ablauf von Redis 4.0 wird nicht verwendet. Löschen (lazyfree-lazy-expire ja), es besteht die Möglichkeit, Redis zu blockieren.

Die Generierung von Bigkeys:
Im Allgemeinen ist die Generierung von Bigkeys auf ein unsachgemäßes Programmdesign oder eine unklare Vorhersage des Datenumfangs zurückzuführen.

So optimieren Sie Bigkey

  1. Große Liste aufteilen
    : list1, list2, ... listN
    großer Hash: Man kann sagen, dass Daten in Segmenten gespeichert werden, z. B. in großen Schlüsseln. Unter der Annahme, dass 1 Million Daten gespeichert sind, können sie in 200 Schlüssel aufgeteilt werden Schlüssel speichert 5000 Die Datenmenge
  2. Wenn Bigkey unvermeidlich ist, überlegen Sie, ob Sie jedes Mal alle Elemente entfernen möchten (manchmal ist beispielsweise nur hmget anstelle von hgetall erforderlich). Das Gleiche gilt für das Löschen. Versuchen Sie, eine elegante Methode zu verwenden, um damit umzugehen.
  3. [Empfehlung]: Kontrollieren Sie den Lebenszyklus des Schlüssels. Redis ist kein Mülleimer. Es wird empfohlen, „expire“ zu verwenden, um die Ablaufzeit festzulegen (wenn die Bedingungen dies zulassen, kann die Ablaufzeit verteilt werden, um einen zentralen Ablauf zu verhindern).

5. Verwendung des Redis-Verbindungspools

Die Verwendung einer Datenbank mit einem Verbindungspool kann die Verbindung effektiv steuern und gleichzeitig die Effizienz verbessern. Die Standardverwendungsmethode:
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
1) maxTotal: die maximale Anzahl von Verbindungen
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein

2) Erklärung zu maxIdle und minIdle
Fügen Sie hier eine Bildbeschreibung ein
: maxTotal: 100 maxIdle: 20 minIdle: 10

  • Der Redis-Thread-Pool ist ein Lazy-Loading-Prozess. Verbindungen werden nur erstellt, wenn sie verwendet werden, und die Verbindungen werden gleichzeitig im Thread-Pool platziert.
  • Wenn eine Verbindung erstellt werden muss, beträgt der maximale Thread-Pool 100. Nach Abschluss der Ausführung wird die Thread-Pool-Verbindung schrittweise freigegeben und die Verbindung wird auf 20 Verbindungen wiederhergestellt. Nur wenn eine spezielle Konfiguration vorgenommen wird, wird die Verbindung wird auf 10 freigegeben. Im Allgemeinen wird maxIdle als Standardwert verwendet.allow;
  • Aber minIdle hat noch eine andere Funktion: Es ist praktisch, den Thread-Pool aufzuwärmen
  • Wenn unmittelbar nach dem Systemstart viele Anfragen eingehen, können Sie den Redis-Verbindungspool aufwärmen, z. B. schnell einige Redis-Verbindungen erstellen, einfache Befehle ausführen, ähnlich wie bei ping(), und die inaktiven Verbindungen im schnell erhöhen Verbindungspool auf die Anzahl von minIdle.

Fügen Sie hier eine Bildbeschreibung ein

6. Redis verfügt über drei Löschstrategien für abgelaufene Schlüssel

  1. Passives Löschen: Beim Lesen/Schreiben eines abgelaufenen Schlüssels wird die Strategie des verzögerten Löschens ausgelöst, um den abgelaufenen Schlüssel direkt zu löschen
  2. Aktives Löschen: Da die Strategie des verzögerten Löschens nicht garantieren kann, dass kalte Daten rechtzeitig gelöscht werden, löscht Redis regelmäßig aktiv einen Stapel abgelaufener Schlüssel
  3. Wenn der aktuell verwendete Speicher das maximale Speicherlimit überschreitet, wird eine aktive Bereinigungsstrategie ausgelöst

Die aktive Reinigungsstrategie implementierte vor Redis 4.0 insgesamt 6 Speichereliminierungsstrategien und fügte nach 4.0 zwei Strategien für insgesamt 8 Typen hinzu: Der LRU-Algorithmus (Least Recent Used, am wenigsten kürzlich verwendet) eliminiert Daten, auf die seit einem Jahr nicht
Fügen Sie hier eine Bildbeschreibung ein
zugegriffen
wurde long time , wobei die letzte Zugriffszeit als Referenz verwendet wird.
Der LFU-Algorithmus (Least Frequently Used)
eliminiert die Daten, auf die im letzten Zeitraum am seltensten zugegriffen wurde, und verwendet dabei die Häufigkeit als Referenz.

Konfigurieren Sie maxmemory-policy (der Standardwert ist noeviction) entsprechend Ihrem eigenen Geschäftstyp. Es wird empfohlen, volatile-lru zu verwenden.
Wenn der maximale Speicher nicht festgelegt ist und der Redis-Speicher die physische Speichergrenze überschreitet, werden die Daten im Speicher häufig mit der Festplatte ausgetauscht (Swap), was zu einem starken Leistungsabfall von Redis führt.
Wenn Redis im Master-Slave-Modus ausgeführt wird, führt nur der Master-Knoten die abgelaufene Löschrichtlinie aus und synchronisiert dann den Löschvorgang „del key“ mit dem Slave-Knoten, um Daten zu löschen.

Supongo que te gusta

Origin blog.csdn.net/qq_39944028/article/details/131039041
Recomendado
Clasificación