1. Einführung in verteilte Schlösser
Verteilte Schlösser werden hauptsächlich zum Schutz der gemeinsamen Ressourcen für Prozesse, Hosts und Netzwerke in einer verteilten Umgebung verwendet, um einen gegenseitig ausschließlichen Zugriff zu erhalten, um die Datenkonsistenz zu gewährleisten.
2. Architektur Einführung
Bevor Sie die Verwendung von Zookeeper zur Implementierung verteilter Schlösser einführen, schauen Sie sich zunächst das aktuelle Systemarchitekturdiagramm an
Erläuterung: Der gesamte Bereich links ist ein Zookeeper -Cluster. Locker ist ein anhaltender Knoten von Zookeeper, und Node_1, node_2 und node_3 sind temporäre sequentielle Knoten unter dem anhaltenden Schließknoten. client_1, client_2, client_n bedeutet mehrere clients und service bedeutet freigegebene Ressourcen, die einen gegenseitig ausschließlichen Zugriff erfordern.
Ideen für den Erwerb von verteilten Schlössern
1. Gesamtidee, verteilte Schlösser zu erhalten
Erstellen Sie beim Erwerb einer verteilten Sperre einen temporären sequentiellen Knoten unter dem Schließfachknoten und löschen Sie den temporären Knoten beim Freisetzung der Sperre. Der Client ruft die CreateNode -Methode auf, um temporäre sequenzielle Knoten unter Schließfach zu erstellen, und dann GetChildren ("Locker"), um alle untergeordneten Knoten unter Locker zu bringen. Beachten Sie, dass derzeit kein Beobachter erforderlich ist. Nachdem der Kunde alle untergeordneten Knotenpfade erhalten hat und festgestellt wird, dass die zuvor erstellte untergeordnete Knotennummer die kleinste ist, wird davon ausgegangen, dass der Kunde das Schloss erhalten hat. Wenn Sie feststellen, dass der von Ihnen erstellte Knoten unter allen Kindern des Schließfachs nicht der kleinste ist, bedeutet dies, dass Sie das Schloss nicht erhalten haben. Zu diesem Zeitpunkt muss der Kunde den Knoten kleiner als ihn finden und dann die existent () -Methode darauf aufrufen und den Ereignishörer darauf registrieren. Wenn der von Ihnen betroffene Knoten gelöscht wird, erhält der Beobachter des Kunden die entsprechende Benachrichtigung. Zu diesem Zeitpunkt bestimmen Sie erneut, ob der von Ihnen erstellte Knoten die kleinste Seriennummer unter den Locker Child Knode ist. Rugao hat das Schloss erhalten. Wenn nicht, wiederholen Sie die obigen Schritte, um weiterhin einen Knoten zu erhalten, der kleiner als Sie ist, und registrieren Sie sich, um zuzuhören. Im aktuellen Prozess sind immer noch viele logische Urteile erforderlich.
2. Der Kernalgorithmusprozess zum Erwerb verteilter Schlösser
Im Folgenden finden Sie das gleiche Flussdiagramm, um den vollständigen Algorithmus für den Erwerb verteilter Schlösser wie folgt zu analysieren:
Erläuterung: Wenn der Client A ein verteiltes Sperre erwerben möchte, erstellen Sie zuerst einen temporären sequentiellen Knoten (NODE_N) unter Locker und erhalten Sie dann sofort alle (ersten) untergeordneten Knoten unter Locker.
Da mehrere Kunden gleichzeitig um Schlösser konkurrieren, ist die Anzahl der untergeordneten Knoten unter dem Schließfach größer als 1. Für sequentielle Knoten ist das Merkmal, dass nach dem Knotennamen eine numerische Nummer vorhanden ist. Die Anzahl der zuerst erstellten Knoten ist kleiner als die später erstellte. Daher können die untergeordneten Knoten in der Reihenfolge des Suffix des Knotennamens von klein bis groß sortiert werden. Auf diese Weise ist der erste der sequentielle Knoten, der zuerst erstellt wurde. Zu diesem Zeitpunkt repräsentiert es den Kunden, der zuerst nach dem Schloss strebt! Bestimmen Sie zu diesem Zeitpunkt, ob der kleinste Knoten der von Client A erstellte Node_N ist. Wenn ja, bedeutet dies, dass der Kunde a das Schloss erworben hat. Wenn nicht, bedeutet dies, dass das Schloss von anderen Kunden erworben wurde. Daher muss der Client A darauf warten, dass es das Schloss freigibt, dh der Client B, der das Schloss erworben hat, löscht den von ihm erstellten Knoten.
Zu diesem Zeitpunkt werden wir wissen, ob Client B das Schloss veröffentlicht hat, indem wir uns das Löschereignis der sequentiellen Knoten anhören, die kleiner als die node_n -Zeiten sind. In diesem Fall erwirbt der Kunde A alle Kinder unter dem Schließfach und vergleicht sie mit den von selbst erstellten Node_N -Knoten, bis der von selbst erstellte Node_n die kleinste Sequenznummer unter allen Kindern von Locker ist, was bedeutet, dass der Kunde A das Schloss erworben hat!
4. Code -Implementierung von verteilten Sperren basierend auf Zookeeper
1. Definieren Sie eine verteilte Schlossschnittstelle
Die definierte verteilte Sperrschnittstelle lautet wie folgt:
Die öffentliche Schnittstelle DistributedLock { / ** Erfassen Sie das Schloss, wenn es nicht erhalten wird, warten Sie* / public void Acquire () Ausnahme; / *** Erwerben Sie das Schloss bis zum Zeitpunkt* @Param Timeout -Zeit* @param Einheit Einheit Zeit Parametereinheit* @return, ob das Schloss erhalten wird / *** die Sperre veröffentlichen* @Throws Exception*/ public void release () löst Ausnahme aus;}2. Definieren Sie einen einfachen Mutex
Definieren Sie eine Mutex -Sperrklasse, implementieren Sie die oben definierte Sperrschnittstelle und erben Sie eine basisklassenbasierte Verschiebung. Diese Basisklasse wird hauptsächlich verwendet, um mit Zookeeper zu interagieren, einschließlich einer Methode, um zu versuchen, das Schloss und eine Release -Sperre zu erwerben.
/** Die spezifische Implementierung der Sperrschnittstelle wird hauptsächlich durch den ererbten übergeordneten klassenbasierten verteilten Verschiebungsschock erreicht. Die übergeordnete Klasse wird auf der Grundlage der spezifischen Details von Zookeeper implementiert, um verteilte Sperren zu implementieren. Erstellen Sie temporäre sequenzielle Knoten unter diesem Knoten, um verteilte Sperren zu implementieren*/ private endgültige String -Basispath; /*Sperrname Präfix. Beispielsweise starten die unter Schließfach erstellten sequentiellen Knoten mit Lock-, was die Filterung irrelevanter Knoten erleichtert. /* Wird verwendet, um die erfolgreichen sequentiellen Knoten zu speichern, die von einem Client unter Schließfach erstellt wurden, für nachfolgende verwandte Operationen (z. B. Urteilsvermögen)*/ private String OurlockPath; /*** Wird verwendet, um Sperrressourcen zu erwerben und Sperren durch die Sperrenakquisitionsmethode der Elternklasse zu erhalten. Weitere Informationen finden Sie in der Implementierung von Versuche. OurlockPath = Versuche (Zeit, Einheit); Rückgabe OurlockPath! = NULL; } /*** Geben Sie das Zookeeper -Client -Verbindungsobjekt ein und Basepath* @param Client Zookeeper Client -Verbindungsobjekt* @param Basepath Basepath ist ein persistierter Knoten* /public SimpleDistributedLockmutex (ZKClientExt Client, String Basepath). Node Child Node *Speichern Sie die Referenz von Basepath auf das aktuelle Klassenattribut */ Super (Client, Basepath, Lock_Name); this.basepath = basepath; } /** das Schloss bis zur Zeitüberschreitung zu erfassen, und eine Ausnahme wird nach dem Timeout* /public void Acquire () Ausnahme ausgelöst. }} / *** Erwerben Sie die Sperre mit Timeout* / public boolean erwerben (lange Zeit, Zeiteinheit) Ausnahme {return InternalLock (Zeit, Einheit); } / ** die Sperre veröffentlichen* / public void release () löst eine Ausnahme aus {releaSelock (urlockPath); }}3. Details zur Implementierung verteilter Sperren
Die Schlüssellogik für den Erwerb verteilter Sperren basiert verteilt, die die Details der Implementierung verteilter Sperren basierend auf Zookeeper implementiert.
public klassenbasierte Verschiebung verteilt {private endgültige zkclientext Client; privater endgültiger Stringweg; private endgültige Streicher Basispath; private endgültige String -Lockkname; private statische endgültige Ganzzahl max_retry_count = 10; public basedSistributedLock (ZKClientExt Client, String -Pfad, String -Lockname) {this.client = client; this.basepath = path; this.path = path.concat ("/"). concat (lockkname); this.lockname = lockkname; } private void DeleteOurPath (String OurPath) löst eine Ausnahme aus {client.delete (uRpath); } private String createLockNode (Zkclient Client, String Pfad) löst Ausnahme aus {return client.createephemeralsequential (Pfad, Null); } / ** * Kernmethode zum Erhalten von Schloss * @param startMillis * @param Millistowait * @param ucne path * @return * @throws Exception * / privat boolean waitolock (long startmillis, long Millistowait, String Ourpath) wirft Ausnahme aus {boolean havethelock = false; boolean dodelete = false; Versuchen Sie {while (! havethelock) {// Diese Methode implementiert die Erfassung aller sequentiellen Knoten unter dem Schließfachknoten und sortiert von kleinen bis großen Liste <string> childhes = userdortedChildren (); String sequencenoDename = ucapath.substring (Basepath.length ()+1); // Berechnen Sie die Sortierposition der vom Kunden erstellten Bestellknoten in allen untergeordneten Knoten des Schließfachs. Wenn die Sortierung 0 ist, bedeutet dies, dass das Schloss erhalten wurde. int ourIndex = children.indexof (sequencenodename); /*Wenn der [temporäre] Bestellknoten, den ich zuvor erstellt habe, nicht in GetortedChildren gefunden wurde, bedeutet dies, dass der von uns erstellte Knoten aufgrund einer Netzwerkblitzbreche gelöscht werden kann. Die Ausnahme muss geworfen werden. Lassen Sie das vorherige Level das vorherige Level verarbeiten, um die Ausnahme zu fangen und die angegebene Anzahl von Wiederholungen auszuführen. Siehe die Versuchs -Methode in der nachfolgenden Versuchs -Methode*/ if (ourIndex <0) {throw New Zknonodeexception ("nicht gefunden:" + sequencenodeName); } // Wenn der vom aktuelle Client erstellte Knoten in der Liste der Locker Child Node -Liste größer als 0 ist, bedeutet dies, dass andere Clients das Sperre erfasst haben //. Der aktuelle Client muss darauf warten, dass andere Clients die Sperre veröffentlichen, boolean isGetHelock = ourIndex == 0; // Wie können Sie feststellen, ob andere Kunden das Schloss veröffentlicht haben? Holen Sie sich den Knoten kleiner als sich selbst aus der Liste der untergeordneten Knoten und richten Sie eine Hörsitzung für IT String pathToWatch = isgetthelock ein? NULL: Children.get (OurIndex - 1); if (isgettHelock) {havethelock = true; } else {// Wenn der kleinere Knoten gelöscht wird, bedeutet dies, dass der Knoten des aktuellen Clients der kleinste sein sollte. Verwenden Sie also CountdownLatch, um die Warte -String -String -Vorgängersequenzpath = Basepath .Concat ("/") .Concat (Pathtowatch) zu realisieren. Final Countdownlatch Latch = New Countdownlatch (1); Final IzkDatalistener PriorListener = new izkdatalistener () {// Wenn ein kleines Knoten -Löschereignis stattfindet, lassen Sie Countdownlatch enden und warten // zu diesem Zeitpunkt müssen Sie das Programm wieder zurückgeben und ein neues Urteil fällen! public void handledatadeleted (String datapath) löst Ausnahme {latch.countdown () aus; } public void handledatachange (String -DataPath, Objektdaten) löst Ausnahme aus {// ignorieren}}; Versuchen Sie {// Ausnahme, wenn der Knoten nicht client.Subcribedatachanges (vorherige SequenzPath, vorheriger Listener) existiert; if (Millistowait! startMillis = system.currentTimemillis (); if (Millistowait <= 0) {dodelete = true; // zeitlich abgestimmt - Löschen Sie unsere Knotenpause; } latch.await (Millistowait, TimeUnit.MicroSeconds); } else {latch.await (); }} catch (zknonodeexception e) {// ignorieren} endlich {client.unSubScribedatachanges (vorherige SequenzPath, vorheriger Listener); }}}}} catch (Ausnahme e) {// Ausnahme muss gelöscht werden dodelete = true; werfen e; } endlich {//, wenn Sie einen Knoten löschen müssen, wenn (dodelete) {DeleteOrPath (yourpath); }} return havethelock; } private String getLockNoDenumber (String Str, String Lockname) {int index = str.lastIndexof (lockname); if (index> = 0) {index += lockkname.length (); Rückgabeindex <= str.length ()? Str.Substring (Index): ""; } return str; } private list <string> GetortedChildren () löst Ausnahme aus {try {list <string> children = client.getChildren (Basepath); Collectionss.sort (Kinder, neuer Vergleicher <string> () {public int compare (String lhs, String rhs) {return getLocknodenumber (lhs, lockname) .Compareto (getLocknodenumber (rhs, lockname));}}); Kinder zurückgeben; } catch (zknonodeexception e) {client.Createpersistent (Basepath, true); return getortedChildren (); }} Protected void releaselock (String LockPath) löst Ausnahme aus {DeleteOrPath (LockPath); } Protected String VersuchLock (lange Zeit, Zeiteinheit) löst Ausnahme aus {endgültig long startmillis = system.currentTimemillis (); Final Long Millistowait = (Einheit! = NULL)? Einheit.Tomillis (Zeit): Null; String Ourpath = NULL; boolean mashelock = false; boolean isdone = false; int retrycount = 0; // Net Flash Break erfordert erneut, dass (! Isdone) {isdone = true; Versuchen Sie {// createLocknode werden verwendet, um den [temporären] Bestellknoten für den Client zu erstellen, um das Schloss unter Schließfach zu erwerben (Basispath persistierender Knoten). Ourpath = CreateLockNode (Client, Pfad); / *** Diese Methode wird verwendet, um festzustellen, ob das Schloss erhalten wurde, dh, ob die von Ihnen erstellten Ordenknoten die kleinsten unter allen untergeordneten Knoten des Schließfachs sind* Wenn das Schloss nicht erworben wird, warten Sie, bis die Veröffentlichung des Schlosses freigesetzt wird, und versuchen Sie es später erneut, bis das Schloss erworben oder zeitlich ausgegeben wird. } catch (zknonodeexception e) {if (retrycount ++ <max_retry_count) {isdone = false; } else {throw e; }}}} if (mashelock) {return OurPath; } return null; }Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.