Ich muss einen benutzerdefinierten rekursiven Objektsperrmechanismus \ Muster für ein verteiltes System in C # entwickeln. Im Wesentlichen habe ich ein System mit mehreren Knoten. Jeder Knoten verfügt über exklusive Schreibberechtigungen für n- Status-Teile. Der gleiche Status ist auch in schreibgeschützter Form auf mindestens einem anderen Knoten verfügbar . Einige Schreibvorgänge / Aktualisierungen müssen über alle Knoten hinweg atomar sein, während andere Aktualisierungen durch Hintergrundreplikationsprozesse, Warteschlangen usw. konsistent werden.
Für die atomaren Aktualisierungen suche ich nach einem Muster oder Beispielen, mit denen ich ein Objekt effizient als für Schreibvorgänge gesperrt markieren kann , die ich dann verteilen, festschreiben, zurücksetzen usw. kann. Da das System ein hohes Maß an Parallelität aufweist, habe ich Ich gehe davon aus, dass ich in der Lage sein muss, Sperren zu stapeln, die entweder eine Zeitüberschreitung aufweisen oder abgewickelt werden, sobald die Sperren freigegeben werden.
Die Transaktions- oder Messaging-Teile stehen nicht im Mittelpunkt dieser Frage, aber ich habe sie für einen zusätzlichen Kontext bereitgestellt. Wenn dies gesagt ist, können Sie gerne artikulieren, welche Nachrichten Ihrer Meinung nach benötigt werden, wenn Sie möchten.
Hier ist ein vages Beispiel von dem, was ich mir vorgestellt habe, obwohl ich offen für neue Ideen bin, abgesehen von der Implementierung ganz neuer Produkte
thing.AquireLock(LockLevel.Write);
//Do work
thing.ReleaseLock();
Ich dachte darüber nach, Erweiterungsmethoden zu verwenden, die ungefähr so aussehen könnten
public static void AquireLock(this IThing instance, TupleLockLevel lockLevel)
{
//TODO: Add aquisition wait, retry, recursion count, timeout support, etc...
//TODO: Disallow read lock requests if the 'thing' is already write locked
//TODO: Throw exception when aquisition fails
instance.Lock = lockLevel;
}
public static void ReleaseLock(this IThing instance)
{
instance.Lock = TupleLockLevel.None;
}
Um ein paar Details zu klären ...
- Alle Kommunikationen sind TCP / IP unter Verwendung eines binären Anforderungs- / Antwortprotokolls
- Es gibt keine Zwischentechnologien wie Warteschlangen oder Datenbanken
- Es gibt keinen zentralen Masterknoten. In diesem Fall wird die Sperranordnung vom Initiator der Sperre und vom Partner definiert, der die Anforderung mit einer Zeitüberschreitung zur Steuerung ihres Verhaltens berücksichtigt
Hat jemand irgendwelche Vorschläge?
Antworten:
Danke für die Klarstellungen.
In diesem Fall würde ich die Verwendung eines Publish / Subscribe-Modells empfehlen. Googles Chubby Distributed Locking-Protokoll (eine Implementierung von Paxos )
Ich habe noch nie Paxos (oder Chubby) verwendet, aber es scheint eine Open - Source - Implementierung zu sein hier .
Wenn dies nicht funktioniert, können Sie Ihre eigene Version von Paxos implementieren, indem Sie beispielsweise einen der üblichen Verdächtigen in Bezug auf Messaging-Bibliotheken verwenden: die Zero Message Queue Library , RabbitMQ oder ActiveMQ .
Vorherige Antwort:
Die meisten Vorschläge zu SO ( [A] , [B] ) verwenden eine Nachrichtenwarteschlange, um eine maschinenübergreifende Sperrung zu erreichen.
Ihre
AcquireLock
Methode würde etwas, das das Sperrobjekt identifiziert, in die Warteschlange verschieben und vor dem Erfolg nach früheren Instanzen von Sperren suchen. IhreReleaseLock
Methode würde das Sperrobjekt aus der Warteschlange entfernen.SO Benutzer atlantis schlägt vor, in diesem Beitrag , Jeff Key Post für einige Details.
quelle
Mir scheint, Sie haben hier ein paar gemischte Technologien:
Kommunikation (auf die Sie sich im Wesentlichen als 100% zuverlässig verlassen ... was tödlich sein kann)
Sperren / gegenseitiger Ausschluss
Timeouts (zu welchem Zweck)?
Ein Wort der Warnung: Zeitüberschreitungen in verteilten Systemen können mit Gefahren und Schwierigkeiten verbunden sein. Wenn sie verwendet werden, müssen sie sehr sorgfältig eingestellt und verwendet werden, da die wahllose Verwendung von Zeitüberschreitungen kein Problem behebt, sondern nur die Katastrophe aufschiebt. (Wenn Sie sehen möchten, wie Zeitüberschreitungen verwendet werden sollen, lesen und verstehen Sie die Dokumentation zum HDLC-Kommunikationsprotokoll. Dies ist ein gutes Beispiel für eine geeignete und clevere Verwendung in Kombination mit einem cleveren Bitcodierungssystem, mit dem beispielsweise IDLE-Leitungen erkannt werden können.) .
Eine Zeit lang arbeitete ich in verteilten Systemen mit mehreren Prozessoren, die über Kommunikationsverbindungen (nicht TCP, etwas anderes) verbunden waren. Eines der Dinge, die ich gelernt habe, war, dass es als grobe Verallgemeinerung einige gefährliche Orte mit mehreren Programmen gibt:
Das Vertrauen in Warteschlangen endet normalerweise in Tränen (wenn sich die Warteschlange füllt, sind Sie in Schwierigkeiten. AUSSER Sie können eine Warteschlangengröße berechnen, die niemals gefüllt wird. In diesem Fall könnten Sie wahrscheinlich eine Lösung ohne Warteschlange verwenden.)
Das Vertrauen in das Sperren ist schmerzhaft. Versuchen Sie zu überlegen, ob es einen anderen Weg gibt (wenn Sie das Sperren verwenden müssen, lesen Sie in der Literatur nach, dass das verteilte Sperren mit mehreren Prozessoren in den letzten zwei bis drei Jahrzehnten Gegenstand vieler acedemischer Veröffentlichungen war).
Wenn Sie mit dem Sperren fortfahren müssen, dann:
Ich gehe davon aus, dass Sie Timeouts nur als Mittel zur Wiederherstellung des letzten Auswegs verwenden - dh zur Erkennung eines Fehlers des zugrunde liegenden Kommunikationssystems. Ich gehe weiter davon aus, dass Ihr TCP / IP-Kommunikationssystem eine hohe Bandbreite hat und als niedrige Latenz angesehen werden kann (idealerweise Null, aber dies passiert nie).
Was ich vorschlagen würde, ist, dass jeder Knoten eine Konnektivitätsliste anderer Knoten hat, mit denen er eine Verbindung herstellen kann. (Knoten würden sich nicht darum kümmern, woher eine Verbindung kommt.) Die Population der Tabellen, zu denen ein Knoten eine Verbindung herstellen kann, bleibt als separate Sache zum Aussortieren übrig. Sie haben nicht gesagt, ob dies statisch oder anderweitig festgelegt wäre. Praktisch ignoriert werden auch Dinge wie die Zuweisung der IP-Portnummern, bei denen Verbindungen zu einem Knoten kommen würden - es kann gute Gründe geben, Anforderungen nur an einem einzelnen Port oder an mehreren Ports anzunehmen. Dies muss sorgfältig abgewogen werden. Zu den Faktoren gehören implizite Warteschlangen, Reihenfolge, Ressourcennutzung, Betriebssystemtyp und Funktionen.
Sobald Knoten wissen, mit wem sie eine Verbindung herstellen, können sie eine Sperranforderung an diesen Knoten senden und müssen von einer Sperrantwort von diesem Remote-Knoten eine Rückmeldung erhalten. Sie können diese beiden Operationen in einen Wrapper packen, damit er atomar aussieht. Dies hat zur Folge, dass Knoten, die eine Sperre erwerben möchten, einen Anruf wie folgt tätigen:
Die Aufrufe get_lock und release_lock sollten ungefähr so aussehen (im Prinzip):
Bei einem verteilten Schließsystem müssen Sie sehr darauf achten, dass die Arbeitseinheiten, die ausgeführt werden, während eine Sperre gehalten wird, klein und schnell sind, da möglicherweise viele entfernte Knoten auf eine Sperre warten. Dies ist effektiv ein Stop-and-Wait-Multiprozessor- / Kommunikationssystem, das robust ist, aber nicht die höchstmögliche Leistung aufweist.
Ein Vorschlag ist, einen völlig anderen Ansatz zu wählen. Können Sie einen Remoteprozeduraufruf verwenden, bei dem jeder RPC-Aufruf ein Informationspaket enthält, das vom Empfänger verarbeitet werden kann und das die Notwendigkeit von Sperren beseitigt?
Beim erneuten Lesen der Frage sieht es so aus, als ob Sie sich nicht wirklich mit der Kommunikationsseite der Dinge befassen möchten, sondern nur Ihr Sperrproblem lösen möchten.
Meine Antwort scheint daher etwas unangebracht zu sein, aber ich glaube, Sie können Ihr Verriegelungsproblem nicht lösen, ohne auch die Teile darunter richtig zu machen. Analogie: Wenn man ein Haus auf einem schlechten Fundament baut, fällt es herunter ... Irgendwann.
quelle
Ihre Frage kann einfach mit einem verteilten Cache wie NCache implementiert werden. Was Sie benötigen, ist ein pessimistischer Sperrmechanismus, mit dem Sie eine Sperre mithilfe eines Objekts erwerben können. Führen Sie dann Ihre Aufgaben und Vorgänge aus und geben Sie die Sperre frei, damit andere Anwendungen sie später verwenden können.
Schauen Sie sich den folgenden Code an.
Hier würden Sie eine Sperre für einen bestimmten Schlüssel erwerben und dann Aufgaben (von einer oder mehreren Operationen) ausführen und die Sperre schließlich aufheben, wenn Sie fertig sind.
Entnommen aus dem Link: http://blogs.alachisoft.com/ncache/distributed-locking/
quelle