


Wie implementiert man die verteilte Redis-Sperre und welche Anwendungsszenarien gibt es?
Einführung
Sperre ist ein sehr häufiges Werkzeug im Entwicklungsprozess. Sie müssen damit vertraut sein: pessimistische Sperre, optimistische Sperre, exklusive Sperre, faire Sperre, unfaire Sperre usw., wenn Sie es sind Mit Java vertraut Wenn Sie die Sperren noch nicht verstehen, können Sie auf diesen Artikel verweisen: Java-„Sperren“, die erwähnt werden müssen. Für Anfänger ist es jedoch möglicherweise nicht möglich, die Konzepte dieser Sperren zu kennen Aufgrund mangelnder praktischer Berufserfahrung können Sie die drei Schlüsselwörter Volatile, Synchronized und ReentrantLock verwenden, um Thread-Sicherheit in Java zu erreichen erste Runde grundlegender Vorstellungsgespräche (Sie müssen damit vertraut sein).
In einem verteilten System kann die Java-Sperrtechnologie den Code nicht auf zwei Maschinen gleichzeitig sperren, daher muss er durch verteilte Sperren implementiert werden. Auch die kompetente Verwendung verteilter Sperren ist eine Fähigkeit, die von großen Entwicklern beherrscht werden muss.
1. Interviewer:
Haben Sie jemals ein Szenario erlebt, in dem Sie verteilte Sperren verwenden müssen?
Problemanalyse: Diese Frage dient hauptsächlich als Einführung. Sie müssen zunächst verstehen, in welchen Szenarien verteilte Sperren verwendet werden müssen und welche Probleme verteilte Sperren lösen müssen verteilte Sperren.
Die Szenarien für die Verwendung verteilter Sperren müssen im Allgemeinen die folgenden Szenarien erfüllen:
Das System ist ein verteiltes System und Java-Sperren können nicht mehr gesperrt werden.
Betreiben Sie gemeinsam genutzte Ressourcen, z. B. die einzigen Benutzerdaten in der Bibliothek.
Synchroner Zugriff, das heißt, mehrere Prozesse betreiben gleichzeitig gemeinsame Ressourcen.
Antwort: Lassen Sie mich Ihnen ein Beispiel für ein Szenario nennen, in dem ich verteilte Sperren in einem Projekt verwende:
Verbrauchspunkte sind in vielen Systemen verfügbar, darunter Kreditkarten, E-Commerce-Websites, Punkte zum Eintauschen von Geschenken usw. Hier ist der Betrieb von „Verbrauchspunkten“. Dies ist ein typisches Szenario, in dem Sperren erforderlich sind.
Ereignis A:
Am Beispiel der Punkteeinlösung für Geschenke ist der gesamte Prozess des Punkteverbrauchs einfach in 3 Schritte unterteilt:
A1: Der Benutzer wählt das Produkt aus, leitet den Umtausch ein und sendet die Bestellung ab.
A2: Das System liest die verbleibenden Punkte des Benutzers: ermittelt, ob die aktuellen Punkte des Benutzers ausreichen.
A3: Benutzerpunkte werden abgezogen.
Ereignis B:
Das System verteilt Punkte in drei einfachen Schritten an Benutzer:
B1: Berechnen Sie die Punkte, die der Benutzer für den Tag verdient.
B2: Lesen Sie die ursprünglichen Punkte des Benutzers.
B3: Addieren Sie diese Zeit zum Original Punkte Punkte sammeln
Dann stellt sich die Frage, was passiert, wenn der Benutzer Punkte verbraucht und gleichzeitig Punkte sammelt (Benutzerpunkte werden gleichzeitig betrieben)?
Annahme: Während der Benutzer Punkte verbraucht, werden zufällig Punkte berechnet und Punkte an den Benutzer ausgegeben (z. B. basierend auf der Verbrauchsmenge des Benutzers an diesem Tag). Die folgende Logik ist etwas kompliziert. Seien Sie also geduldig und verstehen Sie sie.
Benutzer U hat 1.000 Punkte (die Datenaufzeichnung der Benutzerpunkte kann als gemeinsam genutzte Ressourcen verstanden werden), und diese Einlösung verbraucht 999 Punkte.
Freigeschaltete Situation: Wenn das Ereignis-A-Programm Schritt 2 zum Lesen von Punkten erreicht, beträgt das in Operation A:2 gelesene Ergebnis 1000 Punkte. Es wird beurteilt, dass die verbleibenden Punkte für diese Einlösung ausreichen, und dann wird Schritt 3 A ausgeführt: Für 3 Operationen werden Punkte abgezogen (1000 - 999 = 1). Das normale Ergebnis sollte immer noch 1 Punkt für den Benutzer sein. Zu diesem Zeitpunkt wird jedoch auch Ereignis B ausgeführt, 100 Punkte werden an Benutzer U ausgegeben. Zwei Threads führen dies gleichzeitig aus (synchroner Zugriff, es besteht die folgende Möglichkeit: A:2 -). > B :2 -> A:3 -> B:3 , bevor A:3 abgeschlossen ist (Punkte abgezogen, 1000 - 999), werden die Gesamtpunkte von Benutzer U vom Thread von Ereignis B gelesen und schließlich von Benutzer U Gesamtpunkte Es wurden 1100 Punkte, und ich habe ein Geschenk von 999 Punkten vergeblich eingelöst, was offensichtlich nicht den erwarteten Ergebnissen entsprach.
Manche Leute fragen sich, wie es möglich ist, Benutzerpunkte so zufällig gleichzeitig zu betreiben, und die CPU so schnell ist. Solange es genügend Benutzer gibt und die Parallelität groß genug ist, wird Murphys Gesetz früher oder später in Kraft treten. Es ist nur eine Frage der Zeit, bis der oben genannte Fehler auftritt. Wenn Sie als Entwickler diese versteckte Gefahr lösen möchten, müssen Sie die Verwendung von Fehlern verstehen entsperren.
(Code schreiben ist eine anspruchsvolle Sache!)
Java selbst bietet zwei integrierte Sperrimplementierungen, eine wird von der JVM synchronisiert und die Sperre wird vom JDK bereitgestellt, und viele atomare Operationsklassen sind Threads sicher, wenn Ihre Anwendung Wenn es sich um eine eigenständige Anwendung oder eine Einzelprozessanwendung handelt, können Sie diese beiden Sperren verwenden, um Sperren zu implementieren.
Aber die meisten aktuellen Internet-Unternehmenssysteme sind derzeit verteilt und die mit Java gelieferten Sperren können die Sperranforderungen in einer verteilten Umgebung nicht mehr erfüllen, da der Code auf mehreren Computern bereitgestellt wird Um dieses Problem zu lösen, sind verteilte Sperren entstanden, die auf mehreren physischen Maschinen basieren. Die gemeinsame Lösung basiert auf verteilten Sperren Auf Redis oder ZooKeeper verteiltes Lock.
(Ich kann es nicht genauer analysieren, warum ist der Interviewer nicht zufrieden?)
2. Interviewer:
Redis-Implementierungsmethode für verteilte Sperren
Es gibt derzeit zwei Hauptimplementierungsmethoden, um das Problem der verteilten Sperren zu lösen: 1. Einer basiert auf dem Redis-Cluster-Modus und der andere ist ... 2. Basierend auf dem Zookeeper-Clustermodus.
Priorisieren Sie die Beherrschung dieser beiden, dann werden Sie im Grunde keine Probleme haben, das Vorstellungsgespräch zu meistern.
Antwort:
1. Verteilte Sperre basierend auf Redis
Methode 1: Verwenden Sie den Befehl setnx, um
public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) { // 第一步:加锁 Long result = jedis.setnx(lockKey, requestId); if (result == 1) { // 第二步:设置过期时间 jedis.expire(lockKey, expireTime); } }
Code-Erklärung:
Der Befehl setnx
bedeutet „set“, wenn er nicht vorhanden ist. Wenn das Ergebnis nach erfolgreichem Speichern 1 zurückgibt, bedeutet dies, dass die Einstellung erfolgreich ist . Andere Threads haben es bereits festgelegt. setnx
命令,意思就是 set if not exist,如果lockKey不存在,把key存入Redis,保存成功后如果result返回1,表示设置成功,如果非1,表示失败,别的线程已经设置过了。
expire()
expire()
, legen Sie die Ablaufzeit fest, um einen Deadlock zu verhindern. Gehen Sie davon aus, dass die Sperre einer immer vorhandenen Sperre entspricht, wenn sie nicht gelöscht wird Deadlock. (An dieser Stelle möchte ich dem Interviewer ein „Aber“ sagen) Denken Sie darüber nach: Was sind die Mängel meiner oben genannten Methode? Erklären Sie dem Interviewer weiter ...Das Sperren besteht aus zwei Schritten. Der erste Schritt ist jedis.setnx und der zweite Schritt ist jedis.expire, um die Ablaufzeit festzulegen keine atomare Operation. Wenn das Programm nach Abschluss des ersten Schritts ausgeführt wird, ist eine Ausnahme aufgetreten. Der zweite Schritt jedis.expire(lockKey, ExpireTime) wurde nicht ausgeführt, was bedeutet, dass die Sperre keine Ablaufzeit hat und ein Deadlock auftreten kann. Wie kann dieses Problem verbessert werden? Verbesserung: public class RedisLockDemo { private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; /** * 获取分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */ public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) { // 两步合二为一,一行代码加锁并设置 + 过期时间。 if (1 == jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)) { return true;//加锁成功 } return false;//加锁失败 } }
public static void unLock(Jedis jedis, String lockKey, String requestId) { // 第一步: 使用 requestId 判断加锁与解锁是不是同一个客户端 if (requestId.equals(jedis.get(lockKey))) { // 第二步: 若在此时,这把锁突然不是这个客户端的,则会误解锁 jedis.del(lockKey); } }
public class RedisTool { private static final Long RELEASE_SUCCESS = 1L; /** * 释放分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } }
- Kunde Das Ende ruft die Methode create() auf, um einen temporären Sequenzknoten mit dem Namen „/dlm-locks/lockname/lock-“ zu erstellen.
- Der Client ruft die Methode getChildren("lockname") auf, um alle erstellten untergeordneten Knoten abzurufen.
- Nachdem der Client die Pfade aller untergeordneten Knoten erhalten hat und feststellt, dass der in Schritt 1 erstellte Knoten die kleinste Sequenznummer unter allen Knoten hat, wird er suchen Steht die Nummer in der von ihr erstellten Reihenfolge an erster Stelle, wird davon ausgegangen, dass dieser Client die Sperre erhalten hat und kein anderer Client die Sperre zuvor erhalten hat.
- Wenn der erstellte Knoten nicht der kleinste aller Knoten ist, muss der größte Knoten mit einer kleineren Sequenznummer als der von Ihnen erstellte Knoten überwacht werden Geben Sie den Wartezustand ein. Nachdem sich der überwachte untergeordnete Knoten geändert hat, rufen Sie den untergeordneten Knoten ab und bestimmen Sie, ob die Sperre erhalten werden soll.
方法一:
利用 Mysql 的锁表,创建一张表,设置一个 UNIQUE KEY 这个 KEY 就是要锁的 KEY,所以同一个 KEY 在mysql表里只能插入一次了,这样对锁的竞争就交给了数据库,处理同一个 KEY 数据库保证了只有一个节点能插入成功,其他节点都会插入失败。
这样 lock 和 unlock 的思路就很简单了,伪代码:
def lock : exec sql: insert into locked—table (xxx) values (xxx) if result == true : return true else : return false def unlock : exec sql: delete from lockedOrder where order_id='order_id'
方法二:
使用流水号+时间戳做幂等操作,可以看作是一个不会释放的锁。
Das obige ist der detaillierte Inhalt vonWie implementiert man die verteilte Redis-Sperre und welche Anwendungsszenarien gibt es?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Der Redis -Cluster -Modus bietet Redis -Instanzen durch Sharding, die Skalierbarkeit und Verfügbarkeit verbessert. Die Bauschritte sind wie folgt: Erstellen Sie ungerade Redis -Instanzen mit verschiedenen Ports; Erstellen Sie 3 Sentinel -Instanzen, Monitor -Redis -Instanzen und Failover; Konfigurieren von Sentinel -Konfigurationsdateien, Informationen zur Überwachung von Redis -Instanzinformationen und Failover -Einstellungen hinzufügen. Konfigurieren von Redis -Instanzkonfigurationsdateien, aktivieren Sie den Cluster -Modus und geben Sie den Cluster -Informationsdateipfad an. Erstellen Sie die Datei nodes.conf, die Informationen zu jeder Redis -Instanz enthält. Starten Sie den Cluster, führen Sie den Befehl erstellen aus, um einen Cluster zu erstellen und die Anzahl der Replikate anzugeben. Melden Sie sich im Cluster an, um den Befehl cluster info auszuführen, um den Clusterstatus zu überprüfen. machen

So löschen Sie Redis -Daten: Verwenden Sie den Befehl Flushall, um alle Schlüsselwerte zu löschen. Verwenden Sie den Befehl flushdb, um den Schlüsselwert der aktuell ausgewählten Datenbank zu löschen. Verwenden Sie SELECT, um Datenbanken zu wechseln, und löschen Sie dann FlushDB, um mehrere Datenbanken zu löschen. Verwenden Sie den Befehl del, um einen bestimmten Schlüssel zu löschen. Verwenden Sie das Redis-Cli-Tool, um die Daten zu löschen.

Die Verwendung der REDIS -Anweisung erfordert die folgenden Schritte: Öffnen Sie den Redis -Client. Geben Sie den Befehl ein (Verbschlüsselwert). Bietet die erforderlichen Parameter (variiert von der Anweisung bis zur Anweisung). Drücken Sie die Eingabetaste, um den Befehl auszuführen. Redis gibt eine Antwort zurück, die das Ergebnis der Operation anzeigt (normalerweise in Ordnung oder -err).

Redis verwendet eine einzelne Gewindearchitektur, um hohe Leistung, Einfachheit und Konsistenz zu bieten. Es wird E/A-Multiplexing, Ereignisschleifen, nicht blockierende E/A und gemeinsame Speicher verwendet, um die Parallelität zu verbessern, jedoch mit Einschränkungen von Gleichzeitbeschränkungen, einem einzelnen Ausfallpunkt und ungeeigneter Schreib-intensiver Workloads.

Der beste Weg, um Redis -Quellcode zu verstehen, besteht darin, Schritt für Schritt zu gehen: Machen Sie sich mit den Grundlagen von Redis vertraut. Wählen Sie ein bestimmtes Modul oder eine bestimmte Funktion als Ausgangspunkt. Beginnen Sie mit dem Einstiegspunkt des Moduls oder der Funktion und sehen Sie sich die Codezeile nach Zeile an. Zeigen Sie den Code über die Funktionsaufrufkette an. Kennen Sie die von Redis verwendeten Datenstrukturen. Identifizieren Sie den von Redis verwendeten Algorithmus.

Redis verwendet Hash -Tabellen, um Daten zu speichern und unterstützt Datenstrukturen wie Zeichenfolgen, Listen, Hash -Tabellen, Sammlungen und geordnete Sammlungen. Ernähren sich weiterhin über Daten über Snapshots (RDB) und appendiert Mechanismen nur Schreibmechanismen. Redis verwendet die Master-Slave-Replikation, um die Datenverfügbarkeit zu verbessern. Redis verwendet eine Ereignisschleife mit einer Thread, um Verbindungen und Befehle zu verarbeiten, um die Datenatomizität und Konsistenz zu gewährleisten. Redis legt die Ablaufzeit für den Schlüssel fest und verwendet den faulen Löschmechanismus, um den Ablaufschlüssel zu löschen.

Um eine Warteschlange aus Redis zu lesen, müssen Sie den Warteschlangenname erhalten, die Elemente mit dem Befehl LPOP lesen und die leere Warteschlange verarbeiten. Die spezifischen Schritte sind wie folgt: Holen Sie sich den Warteschlangenname: Nennen Sie ihn mit dem Präfix von "Warteschlange:" wie "Warteschlangen: My-Queue". Verwenden Sie den Befehl LPOP: Wischen Sie das Element aus dem Kopf der Warteschlange aus und geben Sie seinen Wert zurück, z. B. die LPOP-Warteschlange: my-queue. Verarbeitung leerer Warteschlangen: Wenn die Warteschlange leer ist, gibt LPOP NIL zurück, und Sie können überprüfen, ob die Warteschlange existiert, bevor Sie das Element lesen.

Um die Operationen zu sperren, muss die Sperre durch den Befehl setNX erfasst werden und dann den Befehl Ablauf verwenden, um die Ablaufzeit festzulegen. Die spezifischen Schritte sind: (1) Verwenden Sie den Befehl setNX, um zu versuchen, ein Schlüsselwertpaar festzulegen; (2) Verwenden Sie den Befehl Ablauf, um die Ablaufzeit für die Sperre festzulegen. (3) Verwenden Sie den Befehl Del, um die Sperre zu löschen, wenn die Sperre nicht mehr benötigt wird.
