Golden Nine und Silver Ten erscheinen bald. Dieser Artikel wird Ihnen 20 Redisklassische Interviewfragen vorstellen.
Redis, der vollständige englische Name lautet Remote Dictionary Server (Remote Dictionary Service), ist eine Open-Source-Protokolltyp-Schlüsselwertdatenbank, die in ANSI C-Sprache geschrieben ist, das Netzwerk unterstützt, speicherbasiert sein kann und kann kann beibehalten werden und bietet eine API in mehreren Sprachen. [Verwandte Empfehlungen: Redis-Video-Tutorial]
Anders als bei der MySQL-Datenbank werden Redis-Daten im Speicher gespeichert. Seine Lese- und Schreibgeschwindigkeiten sind sehr hoch und können mehr als 100.000 Lese- und Schreibvorgänge pro Sekunde bewältigen. Daher wird Redis häufig beim Caching verwendet. Darüber hinaus wird Redis auch häufig für verteilte Sperren verwendet. Darüber hinaus unterstützt Redis Transaktionen, Persistenz, LUA-Skripte, LRU-gesteuerte Ereignisse und verschiedene Clusterlösungen.
2. Lassen Sie uns über die grundlegenden Datenstrukturtypen von Redis sprechen. Die meisten Freunde wissen, dass Redis die folgenden fünf Grundtypen hat:Hash (Hash)
Hyperloglog
Einführung: String ist der grundlegendste Datenstrukturtyp von Redis. Er ist binärsicher und kann Bilder oder serialisierte Objekte speichern. Der maximale gespeicherte Wert beträgt 512 MB. Einfaches Anwendungsbeispiel: Schlüsselwert festlegencode>, <code>get key
usw.
int (8-Byte lange Ganzzahl)/embstr (kleiner oder gleich 39-Byte-String)/raw (größer als 39-Byte-String)
char[]
implementiert und Redis verwendet die Kapselung set key value
、get key
等int(8字节长整型)/embstr(小于等于39字节字符串)/raw(大于39个字节字符串)
C语言的字符串是char[]
实现的,而Redis使用SDS(simple dynamic string) 封装,sds源码如下:
struct sdshdr{ unsigned int len; // 标记buf的长度 unsigned int free; //标记buf中未使用的元素个数 char buf[]; // 存放元素的坑 }
SDS 结构图如下:
Redis为什么选择SDS结构,而C语言原生的 char[]
不香吗?
举例其中一点,SDS中,O(1)时间复杂度,就可以获取字符串长度;而C 字符串,需要遍历整个字符串,时间复杂度为O(n)
hset key field value
、hget key field
ziplist(压缩列表)
、hashtable(哈希表)
字符串和哈希类型对比如下图:
lpush key value [value ...]
、lrange key start end
SDS (einfache dynamische Zeichenfolge) zadd user:ranking:2021-03-03 Jay 3
Warum Hat Redis die
SDS-Struktur gewählt? Und ist das native char[]
der C-Sprache nicht gut?
Zum Beispiel kann in SDS die Länge des Strings mit der Zeitkomplexität O(1) ermittelt werden, während für C-Strings der gesamte String durchlaufen werden muss und die Zeitkomplexität O(n) beträgt
< h4 data- id="heading-5">Hash (Hash)Einführung: In Redis bezieht sich der Hash-Typ auf v (Wert) selbst, der auch eine Schlüssel-Wert-Paar-Struktur (k-v) istEinfaches Anwendungsbeispiel :
hset key field value
,hget key field
Interne Codierung:ziplist (komprimierte Liste)
,hashtable (Hash-Tabelle)< /code ><li></li>Anwendungsszenarien: Zwischenspeichern von Benutzerinformationen usw. </ul></blockquote><h4 data-id="heading-7">Hinweis</h4>: Wenn hgetall in der Entwicklung verwendet wird und viele Hash-Elemente vorhanden sind, kann dies dazu führen, dass Redis blockiert. Sie können hscan verwenden. Wenn Sie nur einige Felder abrufen möchten, empfiehlt sich die Verwendung von hmget. <p><img src="https://img.php.cn/upload/image/656/664/457/1631501863989751.png" title="1631501863989751.png" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p>Der Vergleich zwischen String- und Hash-Typen ist wie folgt: 🎜🎜<img src="https://img.php.cn/upload/image/984/524/946/16315018485778Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" title="1631501848577830 .png " alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/>🎜<h4 data-id="heading-6">Liste (Liste)🎜🎜🎜Einführung: Der Listentyp (Liste) wird zum Speichern mehrerer geordneter Zeichenfolgen verwendet, einer Liste kann bis zu 2^32-1 Elemente speichern. 🎜🎜Einfache und praktische Beispiele: <code> lpush key value [value ...]
,lrange key start end
🎜🎜Interne Codierung: ziplist (komprimierte Liste), linkedlist (verknüpfte Liste). )🎜 🎜Anwendungsszenarien: Nachrichtenwarteschlange, Artikelliste, 🎜🎜🎜Ein Bild zum Verständnis des Einfügens und Popups des Listentyps: 🎜🎜🎜🎜🎜Listenanwendungsszenarien beziehen sich auf Folgendes: 🎜🎜🎜🎜lpush+lpop= Stack (Stack)🎜🎜lpush +rpop=Queue (Warteschlange)🎜🎜lpsh+ltrim=Capped Collection (begrenzte Sammlung)🎜🎜lpush+brpop=Message Queue (Nachrichtenwarteschlange)🎜🎜🎜🎜Set (Set)🎜🎜🎜🎜
- Einführung: Der Set-Typ wird auch zum Speichern mehrerer Zeichenfolgenelemente verwendet, doppelte Elemente sind jedoch nicht zulässig.
- Einfaches Anwendungsbeispiel:
sadd key element [element ...]
,smembers key
sadd key element [element ...]
、smembers key
- 内部编码:
intset(整数集合)
、hashtable(哈希表)
- 注意点:smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,可以使用sscan来完成。
- 应用场景: 用户标签,生成随机数抽奖、社交需求。
有序集合(zset)
- 简介:已排序的字符串集合,同时元素不能重复
- 简单格式举例:
zadd key score member [score member ...]
,zrank key member
- 底层内部编码:
Interne Kodierung:ziplist(压缩列表)
、skiplist(跳跃表)
intset (ganzzahlige Menge)
,hashtable (Hash-Tabelle)
Hinweise: smembers, lrange und Bei hgetall handelt es sich um relativ umfangreiche Befehle. Wenn zu viele Elemente vorhanden sind und die Möglichkeit besteht, dass Redis blockiert wird, können Sie dies mit sscan vervollständigen.Anwendungsszenarien: Benutzer-Tags, Generierung von Zufallszahlenlotterien, soziale Bedürfnisse.
Zugrunde liegende interne Codierung:
Ordered set (zset)
- Einführung: eine sortierte String-Sammlung, und die Elemente können nicht wiederholt werden
- Einfaches Formatbeispiel:
zadd key score member [ Score Mitglied ...]
,zrank-Schlüsselmitglied
ziplist (komprimierte Liste)
,skiplist (Überspringliste)</code > Code><h2 data-id="heading-10"></h2>Anwendungsszenarien: Rankings, soziale Bedürfnisse (z. B. Benutzer-Likes). <p><img src="https://img.php.cn/upload/image/701/100/216/1631501869718890.png" title="1631501869718890.png" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p>2.2 Drei spezielle Datentypen von Redis<h3 data-id="heading-11"></h3><p>Geo: Die von Redis3.2 eingeführte geografische Standortpositionierung wird zum Speichern geografischer Standortinformationen und zum Bearbeiten der gespeicherten Informationen verwendet. </p><h3 data-id="heading-12">HyperLogLog: Eine Datenstruktur, die für statistische Kardinalitätsalgorithmen verwendet wird, wie z. B. UV für statistische Websites. </h3><p>Bitmaps: Verwenden Sie ein Bit, um den Status eines Elements abzubilden. In Redis basiert die unterste Ebene auf dem String-Typ. Sie können Bitmaps in ein Array mit Bits als Einheit umwandeln. </p><p><img src="https://img.php.cn/upload/image/959/396/733/1631501874129651.png" title="1631501874129651.png" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/>3 Warum so schnell? </p><h4 data-id="heading-13"></h4><p><img src="https://img.php.cn/upload/image/879/413/599/16315018818874Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" title="16315018818874Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/>3.1 Implementierung basierend auf Speicherspeicherung</p><blockquote>Wir alle wissen, dass das Lesen und Schreiben im Speicher viel schneller ist als bei einer auf Speicherspeicherung basierenden Redis-Datenbank. Im Vergleich zur MySQL-Datenbank, bei der Daten auf der Festplatte gespeichert werden, werden Festplatten-I/O eingespart. O Verbrauch. <ul><li>3.2 Effiziente Datenstruktur</li><li>Wir wissen, dass der MySQL-Index zur Verbesserung der Effizienz die B+-Baumdatenstruktur wählt. Tatsächlich kann eine vernünftige Datenstruktur Ihre Anwendung/Ihr Programm schneller machen. Werfen wir zunächst einen Blick auf die Datenstruktur und das interne Codierungsdiagramm von Redis: </li><li></li><li></li>SDS einfache dynamische Zeichenfolge </ul></blockquote><h4 data-id="heading-14"></h4><p></p><h4 data-id="heading-15">Verarbeitung der Zeichenfolgenlänge: Redis erhält die Zeichenfolgenlänge, die zeitliche Komplexität beträgt O(1) , und In der C-Sprache muss es von Anfang an durchlaufen werden, und die Komplexität beträgt O(n); verbrauchen Leistung, und SDS-Änderungen und Speicherplatzerweiterungen erfordern zusätzliche Zuweisung von ungenutztem Speicherplatz, um Leistungsverluste zu reduzieren. </h4><p>Lazy Space Release: Wenn SDS gekürzt wird, wird der überschüssige Speicherplatz durch Free aufgezeichnet, und bei späteren Änderungen wird der in Free aufgezeichnete Speicherplatz direkt zur Reduzierung der Zuweisung verwendet. <img src="https://img.php.cn/upload/image/349/649/661/163150189098463Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" title="163150189098463Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p>Binäre Sicherheit: Redis kann einige Binärdaten und in der C-Sprache vorkommende Zeichenfolgen speichern.<blockquote><ul><li>String: Wenn Zahlen gespeichert werden, wird die Codierung vom Typ int verwendet. Wenn keine Zahlen gespeichert werden, wird eine Zeichenfolge kleiner oder gleich 39 Bytes verwendet. Wenn sie größer als 39 Bytes ist, wird die Rohcodierung verwendet. </li><li>Liste: Wenn die Anzahl der Elemente in der Liste weniger als 512 beträgt und der Wert jedes Elements in der Liste weniger als 64 Byte (Standard) beträgt, verwenden Sie die Ziplist-Kodierung, andernfalls verwenden Sie die Linkedlist-Kodierung. </li><li>Hash: Die Anzahl der Hash-Typ-Elemente sind kleiner als 512. Wenn alle Werte weniger als 64 Bytes sind, verwenden Sie die Ziplist-Codierung, andernfalls verwenden Sie die Hashtable-Codierung. </li><li>Set: Wenn die Elemente im Set alle ganze Zahlen sind und die Anzahl der Elemente weniger als 512 beträgt, verwenden Sie die Intset-Codierung, andernfalls verwenden Sie die Hashtable-Codierung. </li><li>Zset: Wenn die Anzahl der Elemente in der geordneten Menge weniger als 128 beträgt und der Wert jedes Elements weniger als 64 Byte beträgt, verwenden Sie die Ziplist-Codierung, andernfalls verwenden Sie die Skiplist-Codierung (Skiplist) </li></ul></blockquote><h3 data-id="heading-17">3.4 Angemessenes Threading-Modell </h3> <p> <strong>I/O-Multiplexing</strong></p><p><img src="https://img.php.cn/upload/image/222/494/553/1631501897175981.png" title="1631501897175981.png" alt="Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p><blockquote><p>Die Multiple-I/O-Multiplexing-Technologie ermöglicht es einem einzelnen Thread, mehrere Verbindungsanfragen effizient zu verarbeiten, und Redis verwendet Epoll als I/O-Multiplexing-Technologie. Darüber hinaus wandelt das eigene Ereignisverarbeitungsmodell von Redis Verbindungen, Lesevorgänge, Schreibvorgänge und Abschaltungen in Epoll in Ereignisse um, ohne zu viel Zeit mit Netzwerk-E/A zu verschwenden. </p></blockquote><p>Was ist I/O-Multiplexing? </p><blockquote><ul><li>I/O: Netzwerk-I/O</li><li>Multiple: mehrere Netzwerkverbindungen</li><li>Multiplexing: Wiederverwendung desselben Threads. </li><li>IO-Multiplexing ist eigentlich ein synchrones E/A-Modell, das einen Thread implementiert, der mehrere Dateihandles überwachen kann. Sobald ein Dateihandle bereit ist, kann es die Anwendung benachrichtigen, entsprechende Lese- und Schreibvorgänge ohne Dateihandle durchzuführen Die Anwendung wird gesperrt und die CPU wird übergeben. </li></ul></blockquote><p><strong>Single-Threaded-Modell</strong></p><ul><li>Redis ist ein Single-Threaded-Modell und Single-Threading vermeidet unnötigen CPU-Kontextwechsel und den Verbrauch von Konkurrenzsperren. Gerade weil es sich um einen einzelnen Thread handelt, führt die Ausführung eines bestimmten Befehls (z. B. des Befehls hgetall) zu einer Blockierung. Redis ist eine Datenbank für schnelle Ausführungsszenarien. Daher sollten Befehle wie smembers, lrange, hgetall usw. mit Vorsicht verwendet werden. </li><li>Redis 6.0 führt Multithreading ein, um die Geschwindigkeit zu erhöhen, und die Ausführung von Befehlen und Speicheroperationen erfolgt immer noch in einem einzelnen Thread. </li></ul><h3 data-id="heading-18">3.5 Virtueller Speichermechanismus</h3><p>Redis baut den VM-Mechanismus direkt selbst auf. Es ruft keine Systemfunktionen wie normale Systeme auf, wodurch eine gewisse Zeit beim Verschieben und Anfordern verschwendet wird. </p><p><strong>Was ist der virtuelle Speichermechanismus von Redis? </strong></p><blockquote><p>Der virtuelle Speichermechanismus verlagert Daten, auf die selten zugegriffen wird (kalte Daten), vorübergehend vom Speicher auf die Festplatte und gibt so wertvollen Speicherplatz für andere Daten frei, auf die zugegriffen werden muss (heiße Daten). Die VM-Funktion kann die Trennung von heißen und kalten Daten realisieren, sodass sich die heißen Daten noch im Speicher befinden und die kalten Daten auf der Festplatte gespeichert werden. Dadurch kann das Problem einer langsamen Zugriffsgeschwindigkeit vermieden werden, die durch unzureichenden Speicher verursacht wird. </p></blockquote><h2 data-id="heading-19">4. Was ist Cache-Aufschlüsselung, Cache-Penetration, Cache-Lawine? </h2><h3 data-id="heading-20">4.1 Cache-Penetrationsproblem</h3><p>Sehen wir uns zunächst eine gängige Methode zur Verwendung des Caches an: Wenn eine Leseanforderung eingeht, überprüfen Sie zuerst den Cache. Wenn es einen Treffer im Cache gibt, wird dieser direkt zurückgegeben Überprüfen Sie die Datenbank und stellen Sie sie dann ein. Der Wert wird im Cache aktualisiert und dann zurückgegeben. </p><p><img src="https://img.php.cn/upload/image/546/664/907/1631501902654880.png" title="1631501902654880.png" alt="1Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p><p><strong>Cache-Penetration</strong>: bezieht sich auf das Abfragen von Daten, die definitiv nicht vorhanden sind. Da der Cache nicht vorhanden ist, muss er aus der Datenbank abgefragt werden Der Cache führt dazu, dass die nicht vorhandenen Daten bei jeder Anforderung in der Datenbank abgefragt werden, was Druck auf die Datenbank ausübt. </p><blockquote><p>Um es einfach auszudrücken: Wenn auf eine Leseanforderung zugegriffen wird, haben weder der Cache noch die Datenbank einen bestimmten Wert, was dazu führt, dass jede Abfrageanforderung für diesen Wert in die Datenbank eindringt. Dies ist eine Cache-Penetration. </p></blockquote><p>Cache-Penetration wird im Allgemeinen durch die folgenden Situationen verursacht: </p><ul><li><strong>Unangemessenes Geschäftsdesign</strong> Beispielsweise haben die meisten Benutzer keinen Schutz aktiviert, aber jede von Ihnen gestellte Anfrage geht in den Cache und fragt eine bestimmte Benutzer-ID ab Sehen Sie nach, ob es einen Schutz gibt. </li><li><strong>Geschäfts-/Betriebs- und Wartungs-/Entwicklungsfehler</strong>, wie z. B. versehentliches Löschen von Cache- und Datenbankdaten. </li><li><strong>Illegaler Anforderungsangriff durch Hacker</strong> Beispielsweise fabrizieren Hacker absichtlich eine große Anzahl illegaler Anforderungen, um nicht vorhandene Geschäftsdaten zu lesen. </li></ul><p><strong>Wie vermeide ich das Eindringen in den Cache? </strong> Generell gibt es drei Methoden. </p><ul><li>1. Wenn es sich um eine illegale Anfrage handelt, überprüfen wir die Parameter am API-Eingang und filtern illegale Werte heraus. </li><li>2. Wenn die Abfragedatenbank leer ist, können wir einen Nullwert oder einen Standardwert für den Cache festlegen. Wenn jedoch eine Schreibanforderung eingeht, muss der Cache aktualisiert werden, um die Cache-Konsistenz sicherzustellen. Gleichzeitig wird schließlich die entsprechende Ablaufzeit für den Cache festgelegt. (In der Wirtschaft häufig verwendet, einfach und effektiv) </li><li>3. Verwenden Sie den Bloom-Filter, um schnell festzustellen, ob Daten vorhanden sind. Das heißt, wenn eine Abfrageanforderung eingeht, beurteilt sie zunächst mithilfe des Bloom-Filters, ob der Wert vorhanden ist, und prüft dann weiter, ob er vorhanden ist. </li></ul><blockquote><p>Bloom-Filterprinzip: Es besteht aus einem Bitmap-Array mit einem Anfangswert von 0 und N Hash-Funktionen. Führen Sie N Hash-Algorithmen für einen Schlüssel aus, um N Werte im Bitarray zu erhalten, und setzen Sie sie auf 1. Wenn dann überprüft wird, ob diese spezifischen Positionen alle 1 sind, stellt der Bloom-Filter fest, dass der Schlüssel vorhanden ist . </p></blockquote><h3 data-id="heading-21">4.2 Cache-Snowrun-Problem</h3><p><strong>Cache-Snowrun: </strong> bezieht sich auf die Ablaufzeit einer großen Datenmenge im Cache, die Abfragedaten sind riesig und die Anforderungen greifen direkt auf die Datenbank zu, was zu übermäßigem Druck auf die Datenbank führt und sogar Ausfallzeiten. </p><ul><li>Cache-Schneefall wird im Allgemeinen dadurch verursacht, dass eine große Datenmenge gleichzeitig abläuft. Aus diesem Grund kann das Problem gelöst werden, indem die Ablaufzeit gleichmäßig eingestellt wird, dh die Ablaufzeit relativ diskret gestaltet wird. Wenn Sie einen größeren Festwert + einen kleineren Zufallswert verwenden, 5 Stunden + 0 bis 1800 Sekunden. </li><li>Redis-Fehler können auch zu Cache-Schneefall führen. Dies erfordert den Aufbau eines Redis-Hochverfügbarkeitsclusters. </li></ul><h3 data-id="heading-22">4.3 Cache-Aufschlüsselungsproblem</h3><p><strong>Cache-Aufschlüsselung: </strong> bezieht sich darauf, dass der Hotspot-Schlüssel zu einem bestimmten Zeitpunkt abläuft und es zu diesem Zeitpunkt zufällig eine große Anzahl gleichzeitiger Anforderungen für diesen Schlüssel gibt, also a Eine große Anzahl von Anfragen wird auf die Datenbank übertragen. </p><p>Der Cache-Ausfall sieht ein wenig ähnlich aus. Tatsächlich besteht der Unterschied darin, dass der Cache-Absturz bedeutet, dass die Datenbank übermäßig belastet ist oder sogar ausfällt. Es kann davon ausgegangen werden, dass die Aufschlüsselung eine Teilmenge des Cache-Snowruns ist. Einige Artikel glauben, dass der Unterschied zwischen den beiden darin besteht, dass die Aufschlüsselung auf einen bestimmten Hotkey-Cache abzielt, während Xuebeng auf viele Schlüssel abzielt. </p><p>Es gibt zwei Lösungen: </p><ul><li><strong>1. Verwenden Sie das Mutex-Sperrschema</strong>. Wenn der Cache fehlschlägt, laden Sie die Datenbankdaten nicht sofort, sondern verwenden bei erfolgreicher Rückkehr zunächst einige atomare Operationsbefehle, z. B. (Setnx von Redis), um den Vorgang durchzuführen. Laden Sie bei Erfolg die Datenbankdatenbankdaten und richten Sie den Cache ein. Versuchen Sie andernfalls erneut, den Cache abzurufen. </li><li><strong>2. „Lässt nie ab“</strong> bedeutet, dass keine Ablaufzeit festgelegt ist, aber wenn die Hotspot-Daten bald ablaufen, aktualisiert der asynchrone Thread die Ablaufzeit und legt sie fest. </li></ul><h2 data-id="heading-23">5. Was ist das Hotkey-Problem und wie löst man das Hotkey-Problem</h2><p><strong>Was ist der Hotkey</strong>? In Redis bezeichnen wir Schlüssel mit hoher Zugriffshäufigkeit als Hotspot-Schlüssel. </p><p>Wenn aufgrund eines besonders großen Anforderungsvolumens eine Anfrage nach einem bestimmten Hotspot-Schlüssel an den Server-Host gesendet wird, kann dies zu unzureichenden Host-Ressourcen oder sogar Ausfallzeiten führen und somit die normalen Dienste beeinträchtigen. </p><p><img src="https://img.php.cn/upload/image/681/859/235/163150190722212Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" title="163150190722212Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" alt="1Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/></p><p>Und wie wird der Hotspot-Schlüssel generiert? Dafür gibt es zwei Hauptgründe: </p><blockquote><ul><li>Die von den Benutzern verbrauchten Daten sind viel größer als die produzierten Daten, wie z. B. Flash-Sales, aktuelle Nachrichten und andere Szenarien, in denen mehr gelesen und weniger geschrieben wird. </li><li>Das Anforderungs-Sharding ist konzentriert, was die Leistung eines einzelnen Redi-Servers übersteigt. Wenn beispielsweise der Schlüssel mit dem festen Namen und der Hash auf denselben Server fallen, ist der Umfang des sofortigen Zugriffs enorm, übersteigt den Maschinenengpass und verursacht Hot Schlüsselprobleme. </li></ul></blockquote><p>Wie erkennt man also Hotkeys in der täglichen Entwicklung? </p><blockquote><ul><li>Bestimmen Sie, welche Hotkeys auf Erfahrung basieren. </li><li>Client-Statistikberichte; </li><li>Reporting an die Service-Agent-Ebene. </li></ul></blockquote><p>Redis-Cluster-Erweiterung: Shard-Kopien hinzufügen, um den Leseverkehr auszugleichen; </p><blockquote>Hotkeys auf verschiedene Server verteilen; <ul><li>Zwischenspeicher der zweiten Ebene, d. h. lokalen JVM-Cache, verwenden, um Redis-Leseanforderungen zu reduzieren. </li><li></li><li>6. Redis-Ablaufstrategie und Speicherbeseitigungsstrategie</li></ul></blockquote><h2 data-id="heading-24"></h2>6.1 Redis-Ablaufstrategie<p><img src="https://img.php.cn/upload/image/196/230/831/163150191159182Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" title="163150191159182Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)" alt="1Zusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse)"/>Wir sind hier</p>. Geben Sie an, dass dieser Schlüssel nach 60 Sekunden abläuft. Wie wird Redis nach 60 Sekunden damit umgehen? Lassen Sie uns zunächst mehrere Ablaufstrategien vorstellen: <h3 data-id="heading-25"></h3>Zeitgesteuerter Ablauf<p><code>set key
的时候,可以给它设置一个过期时间,比如expire key 60
Jeder Schlüssel mit einer Ablaufzeit muss einen Timer erstellen, und der Schlüssel wird sofort gelöscht, wenn die Ablaufzeit erreicht ist. Diese Strategie kann abgelaufene Daten sofort löschen und ist sehr speicherschonend; sie beansprucht jedoch eine große Menge an CPU-Ressourcen für die Verarbeitung abgelaufener Daten, was sich auf die Cache-Reaktionszeit und den Durchsatz auswirkt.
Nur wenn auf einen Schlüssel zugegriffen wird, wird beurteilt, ob der Schlüssel abgelaufen ist, und er wird gelöscht, wenn er abläuft. Diese Strategie kann CPU-Ressourcen maximal einsparen, ist jedoch sehr speicherunfreundlich. In extremen Fällen kann es vorkommen, dass auf eine große Anzahl abgelaufener Schlüssel nicht erneut zugegriffen werden kann, sodass sie nicht gelöscht werden und viel Speicher belegen.
Zu jedem bestimmten Zeitpunkt wird eine bestimmte Anzahl von Schlüsseln im Ablaufwörterbuch einer bestimmten Anzahl von Datenbanken gescannt und die abgelaufenen Schlüssel werden gelöscht. Diese Strategie ist ein Kompromiss zwischen den ersten beiden. Durch Anpassen des Zeitintervalls geplanter Scans und des begrenzten Zeitverbrauchs jedes Scans kann unter verschiedenen Umständen ein optimales Gleichgewicht zwischen CPU- und Speicherressourcen erreicht werden.
Das Expires-Wörterbuch speichert die Ablaufzeitdaten aller Schlüssel mit festgelegter Ablaufzeit, wobei „key“ ein Zeiger auf einen Schlüssel im Schlüsselraum und „value“ die Ablaufzeit ist, die durch den UNIX-Zeitstempel des Schlüssels mit Millisekundengenauigkeit dargestellt wird. Der Schlüsselraum bezieht sich auf alle im Redis-Cluster gespeicherten Schlüssel.
Redis verwendet sowohl Lazy Expiration als auch Periodic Expirationzwei Ablaufstrategien.
Aber wenn beim regulären Löschen viele abgelaufene Schlüssel übersehen werden, wird das verzögerte Löschen nicht verwendet. Im Speicher werden viele abgelaufene Schlüssel angesammelt, was direkt dazu führt, dass der Speicher explodiert. Oder manchmal, wenn das Geschäftsvolumen zunimmt, werden die Redis-Schlüssel stark beansprucht, der Speicher reicht einfach nicht aus und der Betriebs- und Wartungsmitarbeiter vergisst, den Speicher zu erhöhen. Könnte Redis einfach so auflegen? NEIN! Redis schützt sich mit 8 Speichereliminierungsstrategien~
- volatile-lru: Wenn der Speicher nicht ausreicht, um neu geschriebene Daten aufzunehmen, verwenden Sie LRU (zuletzt verwendet) aus dem Schlüssel mit einer Ablaufzeit set)-Algorithmus zur Eliminierung;
- allkeys-lru: Wenn der Speicher nicht ausreicht, um neu geschriebene Daten aufzunehmen, wird der LRU-Algorithmus (zuletzt verwendet) zur Eliminierung aus allen Schlüsseln verwendet.
- volatile-lfu: Neu hinzugefügt in Version 4.0: Wenn der Speicher nicht ausreicht, um neu geschriebene Daten aufzunehmen, wird der LFU-Algorithmus verwendet, um Schlüssel unter abgelaufenen Schlüsseln zu löschen.
- allkeys-lfu: Neu in Version 4.0: Wenn der Speicher nicht ausreicht, um die neu geschriebenen Daten aufzunehmen, wird der LFU-Algorithmus verwendet, um alle Schlüssel zu entfernen.
- volatile-random: Wenn der Speicher nicht ausreicht, um die neu geschriebenen Daten aufzunehmen Neu geschriebene Daten, aus dem Schlüssel mit festgelegter Ablaufzeit, werden die Daten zufällig gelöscht;.
- allkeys-random: Wenn der Speicher nicht ausreicht, um die neu geschriebenen Daten aufzunehmen, werden Daten zufällig aus allen Schlüsseln entfernt.
- volatile-ttl: Wenn der Speicher nicht ausreicht, um die neu geschriebenen Daten aufzunehmen, wird der Schlüssel mit einer festgelegten Ablaufzeit entsprechend der Ablaufzeit gelöscht, und die zuvor abgelaufenen werden zuerst gelöscht;
- noeviction: Der Standardstrategie: Wenn der Speicher nicht ausreicht, um neu geschriebene Daten aufzunehmen, meldet der neue Schreibvorgang einen Fehler.
Wenn wir Redis erwähnen, denken wir natürlich daran, dass mittlere und große Websites im In- und Ausland untrennbar mit dem Cache verbunden sind. Eine angemessene Verwendung des Caches, z. B. das Zwischenspeichern von Hotspot-Daten, kann nicht nur die Zugriffsgeschwindigkeit der Website verbessern, sondern auch den Druck auf die Datenbank-DB verringern. Darüber hinaus bietet Redis im Vergleich zu Memcached auch umfangreiche Datenstrukturen und Persistenzmechanismen wie RDB und AOF, die zu den stärksten gehören.
In heutigen Internetanwendungen gibt es verschiedene Rankings, wie zum Beispiel monatliche Verkaufsrankings von E-Commerce-Websites, Geschenkrankings von sozialen APPs, Abstimmungsrankings von Miniprogrammen usw. Der von Redis bereitgestellte zset
Datentyp kann diese komplexen Rankings implementieren.
Wenn Nutzer beispielsweise jeden Tag Videos hochladen, kann die Rangliste der Likes so gestaltet werden:
zadd user:ranking:2021-03-03 Jay 3
zincrby user:ranking:2021-03-03 Jay 1
zrem user:ranking:2021-03-03 John
zrevrangebyrank user:ranking:2021-03-03 0 2
各大网站、APP应用经常需要计数器的功能,如短视频的播放数、电商网站的浏览数。这些播放数、浏览数一般要求实时的,每一次播放和浏览都要做加1的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。Redis天然支持计数功能而且计数的性能也非常好,可以说是计数器系统的重要选择。
如果一个分布式Web服务将用户的Session信息保存在各自服务器,用户刷新一次可能就需要重新登录了,这样显然有问题。实际上,可以使用Redis将用户的Session进行集中管理,每次用户更新或者查询登录信息都直接从Redis中集中获取。
几乎每个互联网公司中都使用了分布式部署,分布式服务下,就会遇到对同一个资源的并发访问的技术难题,如秒杀、下单减库存等场景。
赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适保存 这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。
消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。
用于数据量上亿的场景下,例如几亿用户系统的签到,去重登录次数统计,某用户是否在线状态等等。腾讯10亿用户,要几个毫秒内查询到某个用户是否在线,能怎么做?千万别说给每个用户建立一个key,然后挨个记(你可以算一下需要的内存会很恐怖,而且这种类似的需求很多。这里要用到位操作——使用setbit、getbit、bitcount命令。原理是:redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,然后这个数组的下标index用来表示用户id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0和1)来构建一个记忆系统。
Redis是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis提供了持久化,即把数据保存到磁盘。
Redis提供了RDB和AOF两种持久化机制,它持久化文件加载流程如下:
RDB,就是把内存数据以快照的形式保存到磁盘上。
什么是快照?可以这样理解,给当前时刻的数据,拍一张照片,然后保存下来。
RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。执行完操作后,在指定目录下会生成一个dump.rdb
文件,Redis 重启的时候,通过加载dump.rdb
文件来恢复数据。RDB触发机制主要有以下几种:
RDB 的优点
RDB缺点
AOF (nur Datei anhängen) Persistenz, Protokollform zum Aufzeichnen jedes Schreibvorgangs, Anhängen an die Datei und erneutes Ausführen der AOF-Datei bei Bedarf Neustartbefehl zum Wiederherstellen von Daten. Es löst hauptsächlich das Echtzeitproblem der Datenpersistenz. Die Standardeinstellung ist nicht aktiviert.
Der Workflow von AOF ist wie folgt:
Atvantations von AOF
DisadVantations von AOF
Wir verwenden Redis im Projekt und werden den Redis-Dienst definitiv nicht an einem einzigen Punkt bereitstellen. Denn sobald die Single-Point-Bereitstellung ausfällt, ist sie nicht mehr verfügbar. Um eine hohe Verfügbarkeit zu erreichen, besteht eine gängige Praxis darin, mehrere Kopien der Datenbank zu kopieren und auf verschiedenen Servern bereitzustellen. Wenn einer von ihnen ausfällt, kann er weiterhin Dienste bereitstellen. Es gibt drei Bereitstellungsmodi für Redis, um eine hohe Verfügbarkeit zu erreichen: Master-Slave-Modus, Sentinel-Modus und Cluster-Modus.
Im Master-Slave-Modus stellt Redis mehrere Maschinen bereit, wobei ein Master-Knoten für Lese- und Schreibvorgänge verantwortlich ist und ein Slave-Knoten nur für Lesevorgänge verantwortlich ist. Die Daten des Slave-Knotens stammen vom Master-Knoten. Das Implementierungsprinzip ist der Master-Slave-Replikationsmechanismus. Die Master-Slave-Replikation umfasst die vollständige Replikation und die inkrementelle Replikation. Wenn der Slave zum ersten Mal eine Verbindung zum Master herstellt oder die Verbindung zum ersten Mal hergestellt wird, wird im Allgemeinen eine vollständige Kopie verwendet. Der vollständige Kopiervorgang ist wie folgt:
1 . Der Slave sendet einen Sync-Befehl an den Master.
2. Nach Erhalt des SYNC-Befehls führt der Master den bgsave-Befehl aus, um die vollständige RDB-Datei zu generieren.
Wenn die Datenmenge auf dem Master-Knoten zunimmt oder abnimmt, wird eine Synchronisierung mit dem Slave-Knoten ausgelöst. Vor der Ausführung dieser Funktion ermittelt der Masterknoten, ob der vom Benutzer ausgeführte Befehl über Datenaktualisierungen verfügt. Wenn eine Datenaktualisierung vorliegt und der Slaveknoten nicht leer ist, wird diese Funktion ausgeführt. Die Funktion dieser Funktion ist: Senden Sie den vom Benutzer ausgeführten Befehl an alle Slave-Knoten
und lassen Sie ihn vom Slave-Knoten ausführen. Der Prozess ist wie folgt:9.2 Sentinel-Modus replicationFeedSalves()
函数,接下来在 Master节点上调用的每一个命令会使用replicationFeedSlaves()
Sobald der Master-Knoten im Master-Slave-Modus aufgrund eines Fehlers keine Dienste bereitstellen kann, muss der Slave-Knoten manuell zum Master-Knoten heraufgestuft werden Benachrichtigen Sie gleichzeitig die Anwendung, um die Master-Knotenadresse zu aktualisieren. Offensichtlich ist diese Methode der Fehlerbehandlung in den meisten Geschäftsszenarien inakzeptabel. Um dieses Problem zu lösen, stellt Redis ab Version 2.8 offiziell die Redis Sentinel-Architektur (Sentinel) bereit.
Sentinel-Modus, ein Sentinel-System, das aus einer oder mehreren Sentinel-Instanzen besteht, das alle Redis-Masterknoten und Slave-Knoten überwachen kann, und wenn der überwachte Masterknoten in den Offline-Zustand wechselt,
automatisch den Offline-Master-A-Slave-Knoten darunter entfernen Der Server wird auf einen neuen Masterknoten aktualisiert). Daher können mehrere Sentinels zur Überwachung von Redis-Knoten verwendet werden, und jeder Sentinel überwacht sich auch gegenseitig.
Einfach ausgedrückt hat der Sentinel-Modus drei Funktionen: Senden Sie Befehle und warten Sie, bis der Redis-Server (einschließlich des Master-Servers und des Slave-Servers) zurückkehrt, um seinen Betriebsstatus zu überwachen;
Sentinel überwacht den Der Master-Knoten ist ausgefallen und schaltet den Slave-Knoten automatisch auf den Master-Knoten um, benachrichtigt dann andere Slave-Knoten über den Veröffentlichungs- und Abonnementmodus, ändert die Konfigurationsdatei und lässt sie den Host wechseln
Die Sentinels überwachen auch jeden andere, um eine hohe Verfügbarkeit zu erreichen.Angenommen, der Hauptserver ist ausgefallen und Sentinel 1 erkennt dieses Ergebnis nicht sofort. Es ist nur so, dass Sentinel 1 subjektiv davon ausgeht, dass der Hauptserver nicht verfügbar ist. Wenn die nachfolgenden Sentinels ebenfalls feststellen, dass der Hauptserver nicht verfügbar ist und die Anzahl einen bestimmten Wert erreicht, findet eine Abstimmung zwischen den Sentinels statt. Das Ergebnis der Abstimmung wird von einem Sentinel veranlasst, einen Failover-Vorgang durchzuführen. Nachdem der Wechsel erfolgreich war, wechselt jeder Sentinel im Publish-Subscribe-Modus den von ihm überwachten Slave-Server zum Host. Dieser Vorgang wird als objektiv offline bezeichnet. Auf diese Weise ist für den Kunden alles transparent.
Der Arbeitsmodus von Sentinel ist wie folgt:
Jeder Sentinel sendet einmal pro Sekunde einen PING-Befehl an den Master, den Slave und andere ihm bekannte Sentinel-Instanzen.
Wenn die Zeit seit der letzten gültigen Antwort auf den PING-Befehl den durch die Option down-after-milliseconds angegebenen Wert überschreitet, wird die Instanz von Sentinel als subjektiv offline markiert.
Wenn ein Master als subjektiv offline markiert ist, müssen alle Sentinels, die diesen Master überwachen, einmal pro Sekunde bestätigen, dass der Master tatsächlich in den subjektiven Offline-Status übergegangen ist.
Wenn eine ausreichende Anzahl von Sentinels (größer oder gleich dem in der Konfigurationsdatei angegebenen Wert) bestätigt, dass der Master innerhalb des angegebenen Zeitraums tatsächlich in einen subjektiven Offline-Zustand eingetreten ist, wird der Master als objektiv offline markiert.
Unter normalen Umständen sendet jeder Sentinel alle 10 Sekunden INFO-Befehle an alle ihm bekannten Master und Slaves.
Wenn der Master von Sentinel als objektiv offline markiert wird, wird die Häufigkeit, mit der Sentinel INFO-Befehle an alle Slaves des Offline-Masters sendet, von einmal alle 10 Sekunden auf einmal jede Sekunde geändert.
Wenn nicht genug davon vorhanden sind Sentinels stimmen zu: Wenn der Master offline ist, wird der objektive Offline-Status des Masters entfernt; wenn der Master erneut eine gültige Antwort auf den PING-Befehl des Sentinel zurückgibt, wird der subjektive Offline-Status des Masters entfernt.
Der Sentinel-Modus basiert auf dem Master-Slave-Modus und realisiert die Lese- und Schreibtrennung. Er kann auch automatisch umschalten und die Systemverfügbarkeit ist höher. Allerdings sind die in jedem Knoten gespeicherten Daten gleich, was Speicher verschwendet und online nicht einfach zu erweitern ist. Aus diesem Grund entstand der Cluster-Cluster, der in Redis 3.0 hinzugefügt wurde und den „verteilten Speicher“ von Redis implementierte. Segmentieren Sie die Daten, was bedeutet, dass Sie auf jedem Redis-Knoten unterschiedliche Inhalte speichern müssen, um das Problem der Online-Erweiterung zu lösen. Darüber hinaus bietet es Replikations- und Failover-Funktionen. Kommunikation von Cluster-Cluster-KnotenEin Redis-Cluster besteht aus mehreren Knoten
Wie kommunizieren die einzelnen Knoten miteinander? Durch dasDer Redis-Cluster-Cluster kommuniziert über das Gossip-Protokoll. Zu den ausgetauschten Informationen gehören Knotenfehler, neue Knotenbeitritte, Master-Slave-Knotenwechselinformationen, Slot-Informationen usw. Häufig verwendete Klatschnachrichten werden in vier Typen unterteilt: Ping, Pong, Meet und Fail.
Meet-Nachricht: Benachrichtigen Sie neue Knoten zum Beitritt. Der Absender der Nachricht benachrichtigt den Empfänger, dem aktuellen Cluster beizutreten. Nachdem die Meet-Nachrichtenkommunikation normal abgeschlossen wurde, tritt der empfangende Knoten dem Cluster bei und führt einen regelmäßigen Ping- und Pong-Nachrichtenaustausch durch.
Ping-Nachricht: Die am häufigsten ausgetauschte Nachricht im Cluster. Jeder Knoten im Cluster sendet jede Sekunde Ping-Nachrichten an mehrere andere Knoten, die verwendet werden, um zu erkennen, ob die Knoten online sind, und um Statusinformationen untereinander auszutauschen.Hash-Slot-AlgorithmusPong-Nachricht: Beim Empfang einer Ping- oder Meet-Nachricht antwortet diese dem Absender als Antwortnachricht, um die normale Kommunikation der Nachricht zu bestätigen. Die Pong-Nachricht kapselt intern ihre eigenen Statusdaten. Ein Knoten kann auch seine eigene Pong-Nachricht an den Cluster senden, um den gesamten Cluster zu benachrichtigen, seinen Status zu aktualisieren. Fehlermeldung: Wenn ein Knoten feststellt, dass ein anderer Knoten im Cluster offline ist, sendet er eine Fehlernachricht an den Cluster. Nach Erhalt der Fehlernachricht versetzen andere Knoten den entsprechenden Knoten in den Offline-Status. Insbesondere kommuniziert jeder Knoten mit anderen Knoten über den
- Cluster-Bus
. Verwenden Sie bei der Kommunikation eine spezielle Portnummer, d. h. die Portnummer des externen Dienstes plus 10000. Wenn die Portnummer eines Knotens beispielsweise 6379 ist, lautet die Portnummer, über die er mit anderen Knoten kommuniziert, 16379. Die Kommunikation zwischen Knoten verwendet ein spezielles Binärprotokoll.
Da es sich um verteilten Speicher handelt, ist der vom Cluster-Cluster verwendete verteilte Algorithmus Konsistenter Hash
? Nein, es ist derSlot-AlgorithmusDie gesamte Datenbank ist in 16384 Slots (Slots) unterteilt. Jedes in Redis eingegebene Schlüssel-Wert-Paar wird entsprechend dem Schlüssel gehasht und einem dieser 16384 Slots zugewiesen. Die verwendete Hash-Map ist ebenfalls relativ einfach. Sie verwendet den CRC16-Algorithmus zur Berechnung eines 16-Bit-Werts und dann Modulo 16384. Jeder Schlüssel in der Datenbank gehört zu einem dieser 16384 Slots, und jeder Knoten im Cluster kann diese 16384 Slots verarbeiten.
Jeder Knoten im Cluster ist für einen Teil der Hash-Slots verantwortlich. Der aktuelle Cluster hat beispielsweise die Knoten A, B und C und die Anzahl der Hash-Slots auf jedem Knoten = 16384/3, dann gibt es:
Im Redis-Cluster-Cluster ist Sie müssen sicherstellen, dass 16384 Steckplätze übereinstimmen. Alle Knoten funktionieren normal. Wenn ein Knoten ausfällt, wird auch der Steckplatz, für den er verantwortlich ist, ungültig und der gesamte Cluster funktioniert nicht.
Um eine hohe Verfügbarkeit sicherzustellen, führt der Cluster-Cluster eine Master-Slave-Replikation ein, und ein Masterknoten entspricht einem oder mehreren Slave-Knoten. Wenn andere Master-Knoten einen Master-Knoten A anpingen und mehr als die Hälfte der Master-Knoten mit A kommunizieren, tritt eine Zeitüberschreitung auf, dann gilt der Master-Knoten A als ausgefallen. Wenn der Master-Knoten ausfällt, wird der Slave-Knoten aktiviert.
Auf jedem Knoten von Redis gibt es zwei Dinge, eines ist der Slot und sein Wertebereich ist 016383. Der andere ist Cluster, der als Cluster-Management-Plug-In verstanden werden kann. Wenn der Schlüssel, auf den wir zugreifen, eintrifft, erhält Redis einen 16-Bit-Wert basierend auf dem CRC16-Algorithmus und nimmt dann das Ergebnis modulo 16384. Jeder Schlüssel in Jiangzi entspricht einem Hash-Slot mit einer Nummer zwischen 0 und 16383. Verwenden Sie diesen Wert, um den Knoten zu finden, der dem entsprechenden Slot entspricht, und springen Sie dann automatisch zum entsprechenden Knoten, um Zugriffsvorgänge durchzuführen.
Obwohl die Daten separat auf verschiedenen Knoten gespeichert werden, wird für den Client der gesamte Cluster als Ganzes betrachtet. Der Client stellt eine Verbindung zu einem beliebigen Knoten her und sieht genauso aus, als würde er eine einzelne Instanz von Redis betreiben. Wenn der vom Client betätigte Schlüssel nicht dem richtigen Knoten zugewiesen ist, gibt Redis die Umleitungsanweisung zurück und zeigt schließlich auf den richtigen Knoten. Dies ähnelt dem 302-Umleitungssprung der Browserseite. FailoverDer Redis-Cluster erreicht eine hohe Verfügbarkeit. Wenn ein Knoten im Cluster ausfällt, wirdFailover verwendet, um sicherzustellen, dass der Cluster normale externe Dienste bereitstellen kann.
Der Redis-Cluster realisiert die Fehlererkennung durch Ping/Pong-Nachrichten. Diese Umgebung umfasstsubjektives Offline und objektives Offline.
Subjektiv offline: Ein Knoten geht davon aus, dass ein anderer Knoten nicht verfügbar ist, d.
Ziel offline: Zeigt an, dass ein Knoten wirklich offline ist. Mehrere Knoten im Cluster gehen davon aus, dass der Knoten nicht verfügbar ist, und erzielen so einen Konsens. Wenn der Master-Knoten, der den Steckplatz hält, ausfällt, muss für den Knoten ein Failover durchgeführt werden.
Fehlerbehebung
: Nachdem der Fehler entdeckt wurde und der Offline-Knoten der Master-Knoten ist, müssen Sie einen seiner Slave-Knoten auswählen, um ihn zu ersetzen, um den Hochwert sicherzustellen Verfügbarkeit des Clusters. Der Prozess ist wie folgt:Qualifikationsprüfung: Überprüfen Sie, ob der Slave-Knoten die Bedingungen zum Ersetzen des ausgefallenen Master-Knotens erfüllt.
选了Redis分布式锁的几种实现方法,大家来讨论下,看有没有啥问题哈。
if(jedis.setnx(key,lock_value) == 1){ //加锁 expire(key,100); //设置过期时间 try { do something //业务请求 }catch(){ } finally { jedis.del(key); //释放锁 } }
如果执行完setnx
加锁,正要执行expire设置过期时间时,进程crash掉或者要重启维护了,那这个锁就“长生不老”了,别的线程永远获取不到锁啦,所以分布式锁不能这么实现。
long expires = System.currentTimeMillis() + expireTime; //系统时间+设置的过期时间 String expiresStr = String.valueOf(expires); // 如果当前锁不存在,返回加锁成功 if (jedis.setnx(key, expiresStr) == 1) { return true; } // 如果锁已经存在,获取锁的过期时间 String currentValueStr = jedis.get(key); // 如果获取到的过期时间,小于系统当前时间,表示已经过期 if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间(不了解redis的getSet命令的小伙伴,可以去官网看下哈) String oldValueStr = jedis.getSet(key_resource_id, expiresStr); if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁 return true; } } //其他情况,均返回加锁失败 return false; }
笔者看过有开发小伙伴是这么实现分布式锁的,但是这种方案也有这些缺点:
jedis.getSet()
,最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。if(jedis.set(key, lock_value, "NX", "EX", 100s) == 1){ //加锁 try { do something //业务处理 }catch(){ } finally { jedis.del(key); //释放锁 } }
这个方案可能存在这样的问题:
if(jedis.set(key, uni_request_id, "NX", "EX", 100s) == 1){ //加锁 try { do something //业务处理 }catch(){ } finally { //判断是不是当前线程加的锁,是才释放 if (uni_request_id.equals(jedis.get(key))) { jedis.del(key); //释放锁 } } }
在这里,判断当前线程加的锁和释放锁是不是一个原子操作。如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁。
一般也是用lua脚本代替。lua脚本如下:
if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end;
这种方式比较不错了,一般情况下,已经可以使用这种实现方式。但是存在锁过期释放了,业务还没执行完的问题(实际上,估算个业务处理的时间,一般没啥问题了)。
分布式锁可能存在锁过期释放,业务没执行完的问题。有些小伙伴认为,稍微把锁过期时间设置长一些就可以啦。其实我们设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。
当前开源框架Redisson就解决了这个分布式锁问题。我们一起来看下Redisson底层原理是怎样的吧:
只要线程一加锁成功,就会启动一个watch dog
看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。
Redis一般都是集群部署的,假设数据在主从同步过程,主节点挂了,Redis分布式锁可能会有哪些问题呢?一起来看些这个流程图:
如果线程一在Redis的master节点上拿到了锁,但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障,一个slave节点就会升级为master节点。线程二就可以获取同个key的锁啦,但线程一也已经拿到锁了,锁的安全性就没了。
为了解决这个问题,Redis作者 antirez提出一种高级的分布式锁算法:Redlock。Redlock核心思想是这样的:
搞多个Redis master部署,以保证它们不会同时宕掉。并且这些master节点是完全相互独立的,相互之间不存在数据同步。同时,需要确保在这多个master实例上,是与在Redis单实例,使用相同方法来获取和释放锁。
我们假设当前有5个Redis master节点,在5台服务器上面运行这些Redis实例。
RedLock的实现步骤:如下
- 1. Ermitteln Sie die aktuelle Zeit in Millisekunden.
- 2. Sperren nacheinander von 5 Masterknoten anfordern. Der Client legt das Zeitlimit für die Netzwerkverbindung und die Antwort fest. Das Zeitlimit sollte kürzer sein als die Ablaufzeit der Sperre. (Unter der Annahme, dass die Ablaufzeit der automatischen Sperre 10 Sekunden beträgt, liegt die Timeout-Zeit im Allgemeinen zwischen 5 und 50 Millisekunden. Nehmen wir an, dass die Timeout-Zeit 50 ms beträgt.) Wenn das Zeitlimit überschritten wird, überspringen Sie den Masterknoten und versuchen Sie es so schnell wie möglich mit dem nächsten Masterknoten.
- 3. Der Client verwendet die aktuelle Zeit abzüglich der Startzeit des Erwerbs der Sperre (d. h. die in Schritt 1 aufgezeichnete Zeit), um die Zeit zu ermitteln, die zum Erwerb der Sperre verwendet wurde. Die Sperre wird nur dann erfolgreich erworben, wenn mehr als die Hälfte (N/2+1, hier 5/2+1=3 Knoten) der Redis-Masterknoten die Sperre erhalten haben und die Nutzungsdauer kürzer als die Ablaufzeit der Sperre ist . (Wie im Bild oben gezeigt, 10s>30ms+40ms+50ms+4m0s+50ms)
- Wenn die Sperre erhalten wird, ändert sich die tatsächliche effektive Zeit des Schlüssels und die Zeit, die zum Erhalten der Sperre benötigt wird, muss abgezogen werden.
- Wenn die Sperrenerfassung fehlschlägt (die Sperre wird nicht auf mindestens N/2+1 Master-Instanzen erworben oder die Sperrenerfassungszeit hat die effektive Zeit überschritten), muss der Client auf allen Master-Knoten entsperren (auch wenn einige Master-Knoten (Sie erhalten die Sperre überhaupt nicht.) Auch wenn die Sperre nicht erfolgreich ist, muss sie dennoch entriegelt werden, um zu verhindern, dass einige Fische durch das Netz rutschen.
Die vereinfachten Schritte sind:
Diese Lösung ist nicht schlecht. Nur während der Ruhephase (z. B. nur 1 Sekunde) können schmutzige Daten vorhanden sein, und allgemeine Unternehmen werden dies akzeptieren. Was aber, wenn das
Löschen des Caches zum zweiten Mal fehlschlägt14.2 Cache-Löschwiederholungsmechanismus
Aufgrund des verzögerten doppelten Löschens schlägt der zweite Schritt des Cache-Löschens möglicherweise fehl, was zu Dateninkonsistenzen führt. Sie können diese Lösung zur Optimierung verwenden: Wenn das Löschen fehlschlägt, löschen Sie es noch einige Male, um sicherzustellen, dass das Löschen des Caches erfolgreich ist. Sie können also einen Wiederholungsmechanismus für den Löschcache einführen
Schreibanforderung zum Aktualisieren der Datenbank Der Cache ist aus bestimmten Gründen fehlgeschlagen.
Löschungs-Cache-Mechanismus erneut versuchen ist in Ordnung, führt aber zu vielen
GeschäftscodeeinbrüchenDie Verwendung von Multi-Threading durch Redis bedeutet nicht, dass Redis weiterhin ein Single-Thread-Modell zur Verarbeitung von Client-Anfragen verwendet. Es verwendet nur Multi-Threading, um das Lesen und Schreiben von Daten sowie die Protokollanalyse zu verarbeiten es verwendet immer noch einen einzelnen Thread, um Befehle auszuführen.
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.
Redis implementiert den Transaktionsmechanismus durch eine Reihe von Befehlen wie MULTI, EXEC, WATCH. Transaktionen unterstützen die gleichzeitige Ausführung mehrerer Befehle und alle Befehle in einer Transaktion werden serialisiert. Während des Transaktionsausführungsprozesses werden die Befehle in der Warteschlange serialisiert und der Reihe nach ausgeführt, und von anderen Clients übermittelte Befehlsanforderungen werden nicht in die Befehlssequenz für die Transaktionsausführung eingefügt.
Kurz gesagt ist eine Redis-Transaktion sequentielle, einmalige und exklusive Ausführung einer Reihe von Befehlen in einer Warteschlange.
Der Vorgang zum Ausführen von Transaktionen in Redis ist wie folgt:Beschreibung | |
---|---|
Alle Befehle innerhalb des Transaktionsblocks ausführen | |
Die Transaktion abbrechen und die Ausführung aller Befehle innerhalb des Transaktionsblocks abbrechen | |
Abbrechen Der WATCH-Befehl überwacht alle Tasten. | |
Überwachen Sie den Schlüssel, bevor die Transaktion ausgeführt wird. |
Das obige ist der detaillierte Inhalt vonZusammenfassung und Teilen von 20 klassischen Interviewfragen zu Redis (mit Antwortanalyse). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!