String: Redis verwendet nicht direkt die traditionelle String-Darstellung der C-Sprache, sondern implementiert einen eigenen abstrakten Typ namens Simple Dynamic String SDS. Die Zeichenfolge in der C-Sprache zeichnet keine eigenen Längeninformationen auf, aber SDS speichert die Längeninformationen, was die Zeit zum Erhalten der Zeichenfolgenlänge von O(N) auf O(1) verkürzt und gleichzeitig einen Pufferüberlauf vermeidet und die Notwendigkeit von Änderungen verringert Zeichen. Die Anzahl der Speicherneuzuweisungen, die für die Länge der Zeichenfolge erforderlich sind.
Verknüpfte Liste: Die Redis-verknüpfte Liste ist eine bidirektionale azyklische verknüpfte Listenstruktur. Viele Veröffentlichungs- und Abonnement-, langsame Abfrage- und Überwachungsfunktionen werden mithilfe verknüpfter Listen implementiert. Die Knoten jeder verknüpften Liste werden durch eine listNode-Struktur dargestellt . Für jeden Knoten gibt es Zeiger auf den vorhergehenden Knoten und den nachfolgenden Knoten, und sowohl der vorhergehende als auch der nachfolgende Knoten des Header-Knotens zeigen auf NULL.
Dictionary-Hashtabelle: eine abstrakte Datenstruktur, die zum Speichern von Schlüssel-Wert-Paaren verwendet wird. Redis verwendet Hash-Tabellen als zugrunde liegende Implementierung. Die Hash-Tabelle verwendet die Kettenadressmethode, um Schlüsselkonflikte zu lösen, und wird mehreren Schlüssel-Wert-Paaren an derselben Indexposition zugewiesen Wenn die Hash-Tabelle erweitert oder verkleinert wird, wird der Rehash-Prozess aus Gründen der Dienstverfügbarkeit nicht auf einmal, sondern schrittweise abgeschlossen.
Sprungliste: Sprungliste ist eine der zugrunde liegenden Implementierungen geordneter Mengen. Sprunglisten werden in Redis verwendet, um geordnete Mengenschlüssel und die interne Struktur von Clusterknoten zu implementieren. Die Redis-Skip-Tabelle besteht aus zskiplist und zskiplistNode. Zskiplist wird zum Speichern von Skip-Tabelleninformationen (Header, Endknoten, Länge usw.) verwendet. Die Ebenenhöhe jeder Skip-Tabelle ist zufällig bis 32. Anzahl: In derselben Sprungtabelle können mehrere Knoten dieselbe Punktzahl enthalten, aber das Mitgliedsobjekt jedes Knotens muss eindeutig sein. Die Knoten werden nach der Größe der Punktzahl sortiert werden nach der Größe des Mitgliedsobjekts sortiert.
Integer-Set-Intset: Eine festgelegte abstrakte Datenstruktur, die zum Speichern ganzzahliger Werte verwendet wird. Es gibt keine doppelten Elemente. Die zugrunde liegende Implementierung ist ein Array.
Ziplist mit komprimierter Liste: Die komprimierte Liste ist eine sequentielle Datenstruktur, die zum Speichern von Speicher entwickelt wurde. Sie kann mehrere Knoten enthalten, und jeder Knoten kann ein Byte-Array oder einen ganzzahligen Wert speichern.
Basierend auf diesen grundlegenden Datenstrukturen kapselt Redis sein eigenes Objektsystem, einschließlich String-Objektzeichenfolge, Listenobjektliste, Hash-Objekt-Hash, Sammlungsobjektsatz und geordneter Sammlungsobjekt-Zset, von denen jedes mindestens eine Basis verwendet Datenstruktur.
redis legt die Codierungsform des Objekts über das Codierungsattribut fest, um die Flexibilität und Effizienz zu verbessern. Redis führt automatisch Optimierungen basierend auf verschiedenen Szenarien durch. Die Kodierung verschiedener Objekte ist wie folgt:
String-Objektzeichenfolge: int integer, Embstr-codierte einfache dynamische Zeichenfolge, rohe einfache dynamische Zeichenfolge
Listenobjektliste: Ziplist, Linkedlist
Hash Objekt-Hash: Ziplist, Hashtable
Sammlungsobjektsatz: Intset, Hashtable
Geordnetes Sammlungsobjekt-Zset: Ziplist, Skiplist
Redis ist sehr schnell und kann Zehntausende von Parallelitäten pro Sekunde unterstützen. Im Vergleich zu MySQL ist die Leistung um ein Vielfaches höher. Die Hauptgründe für die hohe Geschwindigkeit sind:
Komplett basierend auf Speicheroperationen
C-Sprachimplementierung, optimierte Datenstruktur, basierend auf mehreren grundlegenden Datenstrukturen, Redis hat viele Optimierungen vorgenommen und die Leistung ist extrem hoch
Verwenden Sie einen einzelnen Thread, keine Kosten für den Kontextwechsel
Basierend auf einem nicht blockierenden IO-Multiplexing-Mechanismus
Redis verwendet Multithreading Threads verzichten immer noch auf einzelne Threads, um Client-Anfragen zu verarbeiten. Es werden nur Multi-Threads zum Lesen und Schreiben von Daten und zum Parsen von Protokollen verwendet.
Der Zweck besteht darin, dass der Leistungsengpass von Redis im Netzwerk-IO und nicht in der CPU liegt. Durch die Verwendung von Multithreading kann die Effizienz des IO-Lesens und -Schreibens verbessert werden, wodurch die Gesamtleistung von Redis verbessert wird.
Das sogenannte Hotkey-Problem besteht darin, dass es plötzlich Hunderttausende Anfragen für den Zugriff auf einen bestimmten Schlüssel auf Redis gibt. Dies führt dazu, dass der Datenverkehr zu stark konzentriert wird und die Obergrenze der physischen Netzwerkkarte erreicht Der Redis-Server stürzt ab und löst eine Lawine aus.
Lösung für Hotkeys:
Verteilen Sie die Hotkeys im Voraus auf verschiedene Server, um den Druck zu verringern.
Fügen Sie den Cache der zweiten Ebene hinzu und laden Sie die Hotkey-Daten im Voraus in den Speicher. Gehen Sie zur Speicherabfrage
Das Konzept der Cache-Aufschlüsselung besteht darin, dass der gleichzeitige Zugriff eines einzelnen Schlüssels zu hoch ist. Wenn dieser abläuft, werden alle Anforderungen direkt an die Datenbank gesendet. Dies ähnelt dem Problem von Hotkeys Der Punkt ist, dass bei Ablauf alle Anfragen gestellt werden. Klicken Sie einfach auf die Datenbank.
Lösung:
Aktualisierung sperren. Wenn Sie beispielsweise die Abfrage von A anfordern und feststellen, dass er sich nicht im Cache befindet, sperren Sie den Schlüssel A und gehen Sie gleichzeitig zur Datenbank, um die Daten abzufragen und zu schreiben Legen Sie es in den Cache und geben Sie es dann an den Benutzer zurück, damit nachfolgende Anforderungen ausgeführt werden können. Die Daten können aus dem Cache abgerufen werden.
Schreiben Sie die Ablaufzeitkombination als Wert und aktualisieren Sie die Ablaufzeit kontinuierlich auf asynchrone Weise, um diese Art von Phänomen zu verhindern.
Cache-Penetration bedeutet, dass Daten abgefragt werden, die nicht im Cache vorhanden sind. Jede Anfrage trifft auf die Datenbank, als ob der Cache nicht vorhanden wäre.
Um dieses Problem zu beheben, fügen Sie eine Schicht Bloom-Filter hinzu. Der Operationsschritt des Bloom-Filters besteht darin, die Daten über eine Hash-Funktion auf K Punkte im Bitarray abzubilden und diese Punkte zum Speichern der Daten auf 1 zu setzen.
Auf diese Weise wird, wenn der Benutzer A erneut abfragt und der Bloom-Filterwert von A 0 ist, dieser direkt zurückgegeben, und es wird keine Aufschlüsselungsanforderung generiert und an die Datenbank gesendet.
Offensichtlich wird es nach der Verwendung des Bloom-Filters ein Problem geben, das eine Fehleinschätzung ist, da es sich um ein Array selbst handelt und theoretisch mehrere Werte in die gleiche Position fallen können, solange die Länge unseres Wenn das Array lang genug ist, wird eine Fehleinschätzung vermieden. Die Wahrscheinlichkeit einer Beurteilung ist geringer, und diese Art von Problem sollte auf der Grundlage der tatsächlichen Situation behandelt werden.
Wenn zu einem bestimmten Zeitpunkt ein großer Cache-Ausfall auftritt, beispielsweise wenn Ihr Cache-Dienst ausgefallen ist, wird eine große Anzahl von Anforderungen eingehen und direkt die Datenbank treffen, was zum Zusammenbruch des gesamten Systems führen kann , was Lawine genannt wird. Im Gegensatz zu den Pannen- und Hotkey-Problemen bezieht sich das Lawinenproblem auf den gleichzeitigen Ablauf großer Caches.
Mehrere Lösungen für Lawinen:
Stellen Sie unterschiedliche Ablaufzeiten für verschiedene Schlüssel ein, um einen gleichzeitigen Ablauf zu vermeiden.
Strombegrenzung Wenn Redis ausgefallen ist, können Sie den Strom begrenzen, um einen Absturz der Datenbank bei einer großen Anzahl von Anfragen zu vermeiden gleichzeitig
Level-2-Cache, die gleiche Hotkey-Lösung.
Redis verfügt hauptsächlich über zwei Strategien zum Löschen abgelaufener Daten.
Periodisches Löschen
volatile-random: Wählen Sie zufällig den Schlüssel mit Ablaufzeit zur Eliminierung aus.
allkeys-lru: Wählen Sie den zuletzt verwendeten Schlüssel aus dem Schlüssel zur Eliminierung aus Schlüssel vom Schlüssel. Eliminierung
noeviction: Wenn der Speicher den Schwellenwert erreicht, wird ein Fehler für den neuen Schreibvorgang gemeldet
Redis-Persistenzlösungen werden in zwei Typen unterteilt: RDB und AOF.
Der SAVE-Befehl blockiert den Redis-Prozess, bis die RDB-Datei generiert wird. Während des Prozessblockierungszeitraums kann Redis keine Befehlsanfragen verarbeiten, was offensichtlich unangemessen ist.
AOF
AOF unterscheidet sich von RDB und zeichnet den Datenbankstatus auf, indem es die vom Redis-Server ausgeführten Schreibbefehle speichert.
AOF implementiert den Persistenzmechanismus in drei Schritten: Anhängen, Schreiben und Synchronisieren.
Bevor jede Ereignisschleife auf dem Server endet, wird die Funktion „flushAppendOnlyFile“ aufgerufen, um zu bestimmen, ob der Inhalt von aof_buf in der AOF-Datei gespeichert werden soll. Dies kann durch die Konfiguration von appendfsync bestimmt werden.
always ##aof_buf内容写入并同步到AOF文件 everysec ##将aof_buf中内容写入到AOF文件,如果上次同步AOF文件时间距离现在超过1秒,则再次对AOF文件进行同步 no ##将aof_buf内容写入AOF文件,但是并不对AOF文件进行同步,同步时间由操作系统决定
Wenn nicht festgelegt, ist die Standardoption „Everysec“, da immer die sicherste Option ist (es geht nur ein Ereignisschleifen-Schreibbefehl verloren), die Leistung jedoch schlecht ist und der Modus „Everysec“ möglicherweise nur 1 Sekunde Taktdaten verliert Während die Effizienz des No-Modus der von Everysec ähnelt, gehen jedoch alle Schreibbefehlsdaten nach der letzten Synchronisierung der AOF-Datei verloren.
Um eine hohe Verfügbarkeit zu erreichen, reicht eine Maschine definitiv nicht aus. Um eine hohe Verfügbarkeit sicherzustellen, bietet Redis zwei Optionen.
Der Master-Slave-Modus ist die einfachste Lösung, um eine hohe Verfügbarkeit zu erreichen, und der Kern ist die Master-Slave-Synchronisation. Das Prinzip der Master-Slave-Synchronisation ist wie folgt:
Slave sendet Synchronisierungsbefehl an Master
Nachdem der Master die Synchronisierung erhalten hat, führt er bgsave aus und generiert eine vollständige RDB-Datei.
Master zeichnet den Schreibbefehl des Slaves im Cache auf
A sendet eine Meet-Nachricht an B basierend auf der empfangenen IP-Adresse und Portnummer. Knoten B empfängt die Meet-Nachricht und sendet Pong zurück. A weiß, dass B die Meet-Nachricht erhalten hat, sendet eine Ping-Nachricht und den Handshake zurück ist erfolgreich
slot ist ein Bit-Array, die Länge des Arrays beträgt 16384/8 = 2048, und jedes Bit des Arrays wird durch 1 dargestellt, das vom Knoten verarbeitet werden soll, und 0 bedeutet, dass es nicht verarbeitet wird dass Knoten A die Slots 0–7 verarbeitet.
Wenn der Client einen Befehl an den Knoten sendet und feststellt, dass der Steckplatz zum aktuellen Knoten gehört, führt der Knoten den Befehl aus. Andernfalls wird ein MOVED-Befehl an den Client zurückgegeben, um den Client dorthin zu leiten Richtiger Knoten. (Der VERSCHOBEN-Prozess erfolgt automatisch)
Wenn Sie Knoten hinzufügen oder entfernen, ist es auch sehr praktisch, Slots neu zuzuweisen. Redis bietet Tools zur Realisierung der Slot-Migration. Der gesamte Prozess erfolgt vollständig online und erfordert keine Unterbrechung des Dienstes.
Wenn Knoten A eine Ping-Nachricht an Knoten B sendet und Knoten B nicht innerhalb der angegebenen Zeit auf Pong antwortet, markiert Knoten A Knoten B als pfail und vermutet, dass er offline ist, und gleichzeitig Senden Sie den Status von B in Form einer Nachricht an andere Knoten. Wenn mehr als die Hälfte der Knoten B als pfail markieren, wird B als Failover markiert und es wird ein Slave-Knoten mit mehr replizierten Daten angezeigt wird zuerst als Master-Knoten ausgewählt und übernimmt den Slot des Offline-Knotens. Der gesamte Prozess ist dem von Sentinel sehr ähnlich und basiert auf dem Raft-Protokoll.
redis implementiert den Transaktionsmechanismus durch MULTI, EXEC, WATCH und andere Befehle. Der Transaktionsausführungsprozess führt eine Reihe mehrerer Befehle nacheinander aus, und während der Ausführung wird die Transaktion nicht unterbrochen, und der Client wird auch nicht unterbrochen ausführen Weitere Anfragen werden gestellt, bis alle Befehle ausgeführt wurden. Der Ausführungsprozess der Transaktion ist wie folgt:
Der Server empfängt die Clientanforderung und die Transaktion beginnt mit MULTI
Wenn sich der Client im Transaktionsstatus befindet, wird die Transaktion in die Warteschlange gestellt und zurückgegeben an den Client in die Warteschlange gestellt, andernfalls wird er direkt ausgeführt. Führen Sie diesen Befehl aus
Beim Empfang des Client-EXEC-Befehls überwacht der WATCH-Befehl, ob der Schlüssel in der gesamten Transaktion geändert wurde. Wenn ja, gibt er eine leere Antwort an den Client zurück Andernfalls durchläuft Redis die gesamte Transaktionswarteschlange und gibt die Ergebnisse schließlich an den Client zurück. Der WATCH-Mechanismus selbst ist ein CAS-Mechanismus Wenn ein Schlüssel geändert wird, wird das Flag REDIS_DIRTY_CAS geöffnet, woraufhin der Server die Ausführung der Transaktion verweigert.
Das obige ist der detaillierte Inhalt vonWas sind die Fragen und Antworten zum Redis-Interview?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!