Teilen über


Clusterverwaltung in Orleans

Orleans bietet Clusterverwaltung über ein integriertes Mitgliedschaftsprotokoll, das manchmal als Silomitgliedschaft bezeichnet wird. Das Ziel dieses Protokolls besteht darin, dass sich alle Silos (Orleans-Server) auf die Gruppe der derzeit aktiven Silos einigen, fehlerhafte Silos erkennen und neuen Silos den Beitritt zum Cluster gestatten.

Das Protokoll basiert auf einem externen Dienst, um eine Abstraktion von IMembershipTable bereitzustellen. IMembershipTable ist eine flache, nicht SQL-ähnliche, permanente Tabelle, die wir für zwei Zwecke verwenden. Erstens wird sie als Treffpunkt für Silos verwendet, um sich gegenseitig zu finden und damit Orleans-Clients Silos finden können. Zweitens wird sie verwendet, um die aktuelle Mitgliedschaftsansicht (Liste der aktiven Silos) zu speichern, und sie hilft dabei, die Einigung über die Mitgliedschaftsansicht zu koordinieren. Derzeit verfügen wir über 6 Implementierungen von IMembershipTable: basierend auf Azure Table Storage, SQL Server, Apache ZooKeeper, Consul IO, AWS DynamoDB und In-Memory-Emulation für die Entwicklung.

Zusätzlich zur IMembershipTable nimmt jedes Silo an einem vollständig verteilten Peer-to-Peer-Mitgliedschaftsprotokoll teil, das fehlerhafte Silos erkennt und eine Einigung über eine Gruppe aktiver Silos erzielt. Wir beginnen damit, weiter unten die interne Implementierung des Mitgliedschaftsprotokolls von IMembershipTable zu beschreiben, und werden dann später die Implementierung von Orleans erläutern.

Das grundlegende Mitgliedschaftsprotokoll

  1. Beim Start fügt jedes Silo einen Eintrag für sich selbst in eine bekannte, gemeinsam genutzte Tabelle ein, wobei eine Implementierung von IMembershipTable verwendet wird. Eine Kombination aus Siloidentität (ip:port:epoch) und Dienstbereitstellungs-ID wird als eindeutige Schlüssel in der Tabelle verwendet. Die Epoche ist lediglich die Zeit in Takten (Ticks), als dieses Silo gestartet wurde, und somit ist garantiert, dass ip:port:epoch in einer bestimmten Orleans-Bereitstellung eindeutig ist.

  2. Silos überwachen sich gegenseitig direkt über Anwendungs-Pings („are you alive“-heartbeats). Pings werden als direkte Nachrichten von Silo zu Silo über dieselben TCP-Sockets gesendet, über die Silos kommunizieren. Auf diese Weise korrelieren Pings vollständig mit tatsächlichen Netzwerkproblemen und der Serverintegrität. Jedes Silo pingt eine konfigurierbare Gruppe anderer Silos. Ein Silo wählt aus, wer gepingt werden soll, indem es konsistente Hashes für die Identität anderer Silos berechnet und so einen virtuellen Ring aller Identitäten bildet und X Nachfolgersilos auf dem Ring auswählt (dies ist eine bekannte verteilte Methode namens konsistentes Hashing und wird häufig in vielen verteilten Hashtabellen wie Chord DHT verwendet).

  3. Wenn ein Silo S keine Y Pingantworten von einem überwachten Server P erhält, verdächtigt es diesen, indem es seinen Verdacht mit Zeitstempel in die Zeile von P in der IMembershipTable schreibt.

  4. Wenn P innerhalb von K Sekunden mehr als Z Verdachtseinträge erhält, schreibt S, dass P inaktiv ist in die Zeile von P, und sendet eine Anforderung an alle Silos, die Mitgliedschaftstabelle neu zu lesen (was sie in regelmäßigen Abständen sowieso tun).

  5. Ausführlichere Informationen:

    1. Ein Verdacht wird in die IMembershipTable in eine spezielle Spalte in der Zeile geschrieben, die P entspricht. Wenn S P verdächtigt, schreibt er: „at time TTT S suspected P“ (zur Zeit TTT hat S P verdächtigt).

    2. Ein Verdacht reicht nicht aus, um P für inaktiv zu erklären. Sie benötigen Z Verdachtseinträge aus verschiedenen Silos in einem konfigurierbaren Zeitfenster T, in der Regel 3 Minuten, um P für inaktiv zu erklären. Der Verdacht wird unter Verwendung der optimistischen Nebenläufigkeitssteuerung geschrieben, die von der IMembershipTable bereitgestellt wird.

    3. Das verdächtigende Silo S liest die Zeile von P.

    4. Wenn S der letzte Verdächtigende ist (es gab bereits Z minus 1 Verdächtigende innerhalb eines Zeitraums T, wie in der Spalte „Verdacht“ geschrieben), beschließt S, P für inaktiv zu erklären. In diesem Fall fügt sich S selbst der Liste der Verdächtigenden hinzu und schreibt außerdem in die „Status“-Spalte von P, dass P inaktiv (Dead) ist.

    5. Andernfalls fügt sich S, wenn S nicht der letzte Verdächtigende ist, lediglich der Spalte der Verdächtigenden hinzu.

    6. In beiden Fällen verwendet das Rückschreiben die Versionsnummer oder das ETag, die/das gelesen wurde, sodass die Aktualisierungen dieser Zeile serialisiert werden. Falls der Schreibvorgang aufgrund eines Versions-/ETag-Konflikts fehlgeschlagen ist, führt S einen Wiederholungsversuch durch (erneutes Lesen und der Versuch, zu schreiben, es sei denn, P war bereits als inaktiv markiert).

    7. Allgemein betrachtet ist diese Abfolge von „lesen, lokal ändern, zurückschreiben“ eine Transaktion. Dafür verwenden wir jedoch keine Speichertransaktionen. Der „Transaktion“scode wird lokal auf einem Server ausgeführt, und wir verwenden optimistische Nebenläufigkeit, die von der IMembershipTable bereitgestellt wird, um Isolation und Unteilbarkeit (Atomarität) sicherzustellen.

  6. Jedes Silo liest regelmäßig die gesamte Mitgliedschaftstabelle für seine Bereitstellung. Auf diese Weise erfahren Silos über neue beitretende Silos sowie über andere Silos, die für inaktiv erklärt werden.

  7. Konfiguration: Wir stellen eine Standardkonfiguration bereit, die während der Produktionsnutzung bei uns in Azure manuell optimiert wurde. Derzeit ist der Standard: Jedes Silo wird von drei weiteren Silos überwacht, zwei Verdachtseinträge reichen aus, um ein Silo für inaktiv zu erklären, Verdachtseinträge nur aus den letzten drei Minuten (andernfalls sind sie veraltet). Pings werden alle zehn Sekunden gesendet, und Sie müssten drei Pings verpassen, um ein Silo zu verdächtigen.

  8. Perfekte Fehlererkennung erzwingen: Es ist theoretisch möglich, dass ein Silo für inaktiv erklärt wird, wenn es die Kommunikation mit anderen Silos verloren hat, während der Siloprozess selbst noch ausgeführt wird. Um dieses Problem zu lösen, wird das Silo, sobald es in der Tabelle für inaktiv erklärt wurde, von allen als inaktiv eingestuft, auch wenn es nicht inaktiv ist (nur vorübergehend partitioniert, oder Heartbeatnachrichten sind verloren gegangen). Alle hören auf, mit dem Silo zu kommunizieren, und sobald es erfährt, dass es inaktiv ist (indem es seinen neuen Status aus der Tabelle liest), inaktiviert es sich selbst („Suizid“) und beendet seinen Prozess. Aus diesem Grund muss eine Infrastruktur vorhanden sein, um das Silo als neuen Prozess neu zu starten (beim Start wird eine neue Epochennummer generiert). Wenn es in Azure gehostet wird, geschieht dies automatisch. Ist dies nicht der Fall, ist eine andere Infrastruktur erforderlich. Beispielsweise ein Windows-Dienst, der für einen automatischen Neustart bei einem Fehler konfiguriert ist, oder eine Kubernetes-Bereitstellung.

  9. Optimierung, um die Häufigkeit regelmäßiger Tabellenlesevorgänge zu reduzieren und das Informieren aller Silos über neue beitretende und inaktive Silos zu beschleunigen. Jedes Mal, wenn ein Silo etwas erfolgreich in die Tabelle schreibt (Verdacht, neuer Beitritt usw.), sendet es auch an alle anderen Silos – „jetzt die Tabelle neu lesen“. Das Silo teilt anderen NICHT mit, was es in die Tabelle geschrieben hat (da diese Informationen bereits veraltet/falsch sein könnten), es fordert sie lediglich auf, die Tabelle erneut zu lesen. Auf diese Weise erfahren wir sehr schnell von Mitgliedschaftsänderungen, ohne auf den vollständigen regelmäßigen Lesezyklus warten zu müssen. Der regelmäßige Lesevorgang ist weiterhin notwendig, falls die Nachricht „Die Tabelle erneut lesen“ verloren geht.

Eigenschaften des grundlegenden Mitgliedschaftsprotokolls

  1. Kann eine beliebige Anzahl von Fehlern behandeln:

    Unser Algorithmus kann eine beliebige Anzahl von Fehlern (d. h. f<=n) behandeln, einschließlich vollständiger Clusterneustarts. Dies steht im Gegensatz zu „traditionellen“ Paxos-basierten Lösungen, die ein Quorum erfordern, das in der Regel eine Mehrheit darstellt. Wir konnten in Produktionssituationen feststellen, dass mehr als die Hälfte der Silos ausgefallen waren. Unser System blieb dabei funktionsfähig, während die Paxos-basierte Mitgliedschaft nicht in der Lage wäre, Fortschritte zu machen.

  2. Datenverkehr an die Tabelle ist sehr niedrig:

    Die tatsächlichen Pings werden direkt zwischen Servern ausgetauscht und nicht mit der Tabelle. Dies würde viel Datenverkehr generieren und wäre außerdem unter dem Aspekt der Fehlererkennung weniger genau – wenn ein Silo die Tabelle nicht erreichen könnte, würde es das Schreiben seines „I am alive“-Heartbeats verpassen und von anderen inaktiviert („killed“) werden.

  3. Optimierbare Genauigkeit im Vergleich zu Vollständigkeit:

    Obwohl Sie nicht gleichzeitig eine perfekte und genaue Fehlererkennung erzielen können, möchte man doch in der Regel die Möglichkeit haben, die Genauigkeit (ein aktives Silo, sollte nicht für inaktiv erklärt werden) gegenüber der Vollständigkeit (ein Silo, das tatsächlich inaktiv ist, sollte so schnell wie möglich für inaktiv erklärt werden) abzuwägen. Die konfigurierbaren Abstimmungen zum Erklären der Inaktivität und verpasste Pings erlauben, diese beiden gegeneinander abzuwägen. Weitere Informationen finden Sie unter Yale University: Computer Science Failure Detectors.

  4. Skalieren:

    Das grundlegende Protokoll kann Tausende und wahrscheinlich sogar Zehntausende von Servern verarbeiten. Dies steht im Gegensatz zu herkömmlichen Paxos-basierten Lösungen wie Gruppenkommunikationsprotokollen, von denen bekannt ist, dass sie sich nicht über Dutzende hinaus skalieren lassen.

  5. Diagnosen:

    Die Tabelle ist auch sehr praktisch für Diagnosen und Problembehandlungen. Die Systemadministratoren können in der Tabelle sofort die aktuelle Liste der aktiven Silos finden sowie den Verlauf aller inaktivierten („killed“) Silos und aller Verdachtseinträge einsehen. Dies ist besonders nützlich bei der Diagnose von Problemen.

  6. Gründe für die Notwendigkeit von zuverlässigem persistentem Speicher für die Implementierung der IMembershipTable:

    Wir verwenden aus zwei Gründen persistenten Speicher (Azure Table, SQL Server, AWS DynamoDB, Apache ZooKeeper oder Consul IO KV) für die IMembershipTable. Erstens wird sie als Treffpunkt für Silos verwendet, um sich gegenseitig zu finden und damit Orleans-Clients Silos finden können. Zweitens verwenden wir zuverlässigen Speicher, um die Einigung auf die Mitgliedschaftsansicht zu koordinieren. Während wir die Fehlererkennung direkt in Peer-to-Peer-Weise zwischen den Silos durchführen, speichern wir die Mitgliedschaftsansicht in zuverlässigem Speicher und verwenden den Mechanismus zur Nebenläufigkeitssteuerung, der von diesem Speicher bereitgestellt wird, um eine Einigung darüber zu erzielen, wer aktiv und wer inaktiv ist. Auf diese Weise lagert unser Protokoll gewissermaßen das schwierige Problem des verteilten Konsens in die Cloud aus. So nutzen wir die Leistungsfähigkeit der zugrunde liegenden Cloudplattform voll aus und verwenden sie wirklich als Platform-as-a-Service (PaaS).

  7. Was geschieht, wenn die Tabelle für einige Zeit nicht zugänglich ist:

    Wenn der Speicherdienst ausgefallen oder nicht verfügbar ist oder Kommunikationsprobleme mit ihm auftreten, deklariert das Orleans-Protokoll die Silos NICHT versehentlich als inaktiv. Betriebsbereite Silos funktionieren problemlos weiter. Orleans kann ein Silo jedoch nicht als inaktiv deklarieren (wenn durch verpasste Pings festgestellt wird, dass ein Silo inaktiv ist, kann diese Tatsache nicht in die Tabelle geschrieben werden) und auch den Beitritt neuer Silos nicht zulassen. Die Vollständigkeit wird also darunter leiden, aber die Genauigkeit nicht. Die Partitionierung aus der Tabelle wird nie dazu führen, dass Orleans ein Silo fälschlicherweise als inaktiv deklariert. Im Falle einer partiellen Netzwerkpartition (wenn einige Silos auf die Tabelle zugreifen können und andere nicht), könnte es auch vorkommen, dass Orleans ein inaktives Silo als inaktiv deklariert, wobei es aber einige Zeit dauert, bis alle anderen Silos davon erfahren. Doch auch wenn die Erkennung also verzögert sein könnte, wird Orleans niemals ein Silo aufgrund der Nichtverfügbarkeit der Tabelle fälschlicherweise inaktivieren.

  8. Direkte IAmAlive-Schreibvorgänge in die Tabelle nur zu Diagnosezwecken:

    Zusätzlich zu Heartbeats, die zwischen den Silos gesendet werden, aktualisiert jedes Silo regelmäßig eine „I Am Alive“-Spalte in seiner Zeile in der Tabelle. Diese „I Am Alive“-Spalte wird nur für die manuelle Problembehandlung und Diagnose verwendet und nicht vom Mitgliedschaftsprotokoll selbst. Dieses wird in der Regel viel seltener geschrieben (einmal alle 5 Minuten) und dient Systemadministratoren als sehr nützliches Tool, um die Aktivität des Clusters zu überprüfen oder einfach herauszufinden, wann das Silo zuletzt aktiv war.

Erweiterung zum Sortieren von Mitgliedschaftsansichten

Das oben beschriebene grundlegende Mitgliedschaftsprotokoll wurde später um die Unterstützung für sortierte Mitgliedschaftsansichten erweitert. Wir erläutern kurz die Gründe für diese Erweiterung und wie sie implementiert wird. Die Erweiterung ändert nichts am obigen Entwurf. Sie fügt lediglich die Eigenschaft hinzu, dass alle Mitgliedschaftskonfigurationen global vollständig sortiert sind.

Warum ist es nützlich, Mitgliedschaftsansichten zu sortieren?

  • Dies ermöglicht die Serialisierung des Beitritts neuer Silos zum Cluster. Auf diese Weise kann ein Cluster die bidirektionale Konnektivität mit jedem anderen bereits gestarteten Silo überprüfen, wenn ein neues Silo dem Cluster beitritt. Wenn einige der bereits beigetretenen Silos nicht antworten (was möglicherweise auf ein Netzwerkkonnektivitätsproblem mit dem neuen Silo hindeutet), darf das neue Silo nicht beitreten. Dadurch wird sichergestellt, dass zumindest beim Start eines Silos vollständige Konnektivität zwischen allen Silos im Cluster besteht (dies ist implementiert).

  • Protokolle auf höherer Ebene im Silo, z. B. das verteilte Grain-Verzeichnis, können die Tatsache nutzen, dass Mitgliedschaftsansichten sortiert sind, und diese Informationen verwenden, um eine intelligentere Auflösung doppelter Aktivierungen vorzunehmen. Insbesondere wenn das Verzeichnis feststellt, dass zwei Aktivierungen erstellt wurden, als die Mitgliedschaft im Fluss war, kann es sich entscheiden, die ältere Aktivierung zu deaktivieren, die auf der Grundlage der jetzt veralteten Mitgliedschaftsinformationen erstellt wurde.

Erweitertes Mitgliedschaftsprotokoll:

  1. Für die Implementierung dieses Features verwenden wir die Unterstützung für Transaktionen über mehrere Zeilen, die von der MembershipTable bereitgestellt wird.

  2. Wir fügen der Tabelle eine Zeile mit der Mitgliedschaftsversion hinzu, die Tabellenänderungen nachverfolgt.

  3. Wenn Silo S einen Verdacht oder eine Inaktivitätserklärung für Silo P schreiben möchte:

    1. S liest den neuesten Tabelleninhalt. Wenn P bereits inaktiv ist, unternehmen Sie nichts. Anderenfalls:
    2. Schreiben Sie in derselben Transaktion die Änderungen in die Zeile von P, und erhöhen Sie die Versionsnummer, und schreiben Sie sie zurück in die Tabelle.
    3. Beide Schreibvorgänge sind mit ETags bedingt.
    4. Wenn die Transaktion aufgrund eines ETag-Konflikts in der Zeile von P oder in der Versionszeile abgebrochen wird, versuchen Sie es noch mal.
  4. Alle Schreibvorgänge in die Tabelle ändern und erhöhen die Versionszeile. Auf diese Weise werden alle Schreibvorgänge in die Tabelle serialisiert (durch Serialisieren der Aktualisierungen der Versionszeile), und da Silos nur die Versionsnummer erhöhen, werden die Schreibvorgänge auch vollständig in aufsteigender Reihenfolge sortiert.

Skalierbarkeit des erweiterten Mitgliedschaftsprotokolls:

In der erweiterten Version des Protokolls werden alle Schreibvorgänge über eine Zeile serialisiert. Dies kann möglicherweise die Skalierbarkeit des Clusterverwaltungsprotokolls beeinträchtigen, da es das Risiko von Konflikten zwischen gleichzeitigen Tabellenschreibvorgängen erhöht. Um dieses Problem teilweise zu minimieren, führen Silos für alle Schreibvorgänge in die Tabelle Wiederholungsversuche mithilfe exponentiellen Backoffs durch. Wir haben beobachtet, dass die erweiterten Protokolle in einer Produktionsumgebung in Azure mit bis zu 200 Silos reibungslos funktionieren. Wir sind jedoch der Meinung, dass das Protokoll beim Skalieren über tausend Silos hinaus Probleme bekommen könnte. Bei solch großen Setups können die Aktualisierungen der Versionszeile leicht deaktiviert werden, wobei der Rest des Clusterverwaltungsprotokolls im Wesentlichen erhalten bleibt und die Eigenschaft für die vollständige Sortierung aufgegeben wird. Beachten Sie außerdem, dass wir uns hier auf die Skalierbarkeit des Clusterverwaltungsprotokolls beziehen, nicht auf den Rest von Orleans. Wir sind davon überzeugt, dass andere Teile der Orleans-Runtime (Messaging, verteiltes Verzeichnis, Grain-Hosting, Client-zu-Gateway-Konnektivität) weit über Hunderte von Silos hinaus skalierbar sind.

Mitgliedschaftstabelle

Wie bereits erwähnt, wird die Tabelle IMembershipTable als Treffpunkt für Silos verwendet, um sich gegenseitig zu finden und damit Orleans-Clients Silos finden können. Sie hilft außerdem dabei, die Einigung auf die Mitgliedschaftsansicht zu koordinieren. Derzeit verfügen wir über sechs Implementierungen der IMembershipTable: basierend auf Azure Table, SQL Server, Apache ZooKeeper, Consul IO, AWS DynamoDB und In-Memory-Emulation für die Entwicklung.

  1. Azure Table Storage: In dieser Implementierung verwenden wir die Azure-Bereitstellungs-ID als Partitionsschlüssel und die Siloidentität (ip:port:epoch) als Zeilenschlüssel. Zusammen garantieren sie einen eindeutigen Schlüssel pro Silo. Für die Nebenläufigkeitssteuerung verwenden wir die optimistische Nebenläufigkeitssteuerung, basierend auf Azure Table-ETags. Jedes Mal, wenn wir aus der Tabelle lesen, speichern wir das ETag für jede gelesene Zeile und verwenden dieses ETag, wenn wir versuchen, zurückzuschreiben. ETags werden automatisch bei jedem Schreibvorgang vom Azure Table-Dienst zugewiesen und überprüft. Für Transaktionen mit mehreren Zeilen verwenden wir die Unterstützung für Batchtransaktionen, die von Azure Table bereitgestellt wird, wodurch serialisierbare Transaktionen über Zeilen hinweg mit demselben Partitionsschlüssel garantiert werden.

  2. SQL Server: In dieser Implementierung wird die konfigurierte Bereitstellungs-ID verwendet, um zwischen Bereitstellungen zu unterscheiden sowie um zu differenzieren, welche Silos zu welchen Bereitstellungen gehören. Die Siloidentität wird als Kombination von deploymentID, ip, port, epoch in entsprechenden Tabellen und Spalten definiert. Das relationale Back-End verwendet optimistische Nebenläufigkeitssteuerung und Transaktionen, ähnlich wie bei der Vorgehensweise zur Verwendung von ETags in der Azure Table-Implementierung. Die relationale Implementierung erwartet, dass die Datenbank-Engine das verwendete ETag generiert. Im Fall von SQL Server ist das generierte ETag bei SQL Server 2000 eins, das durch einen Aufruf von NEWID() abgerufen wird. Bei SQL Server 2005 und höher wird ROWVERSION verwendet. Orleans liest und schreibt relationale ETags als opake VARBINARY(16)-Tags und speichert sie als base64-codierte Zeichenfolgen im Arbeitsspeicher. Orleans unterstützt Mehrzeileneinfügungen mithilfe von UNION ALL (für Oracle einschließlich DUAL), das derzeit zum Einfügen von Statistikdaten verwendet wird. Die genaue Implementierung und das Konzept für SQL Server finden Sie unter CreateOrleansTables_SqlServer.sql.

  3. Apache ZooKeeper: In dieser Implementierung verwenden wir die konfigurierte Bereitstellungs-ID als Stammknoten und die Siloidentität (ip:port@epoch) als dessen untergeordneten Knoten. Zusammen garantieren sie einen eindeutigen Pfad pro Silo. Für die Nebenläufigkeitssteuerung verwenden wir die optimistische Nebenläufigkeitssteuerung, basierend auf der Knotenversion. Jedes Mal, wenn wir aus dem Stammknoten der Bereitstellung lesen, speichern wir die Version für jeden gelesenen untergeordneten Siloknoten und verwenden diese Version, wenn wir versuchen, zurückzuschreiben. Jedes Mal, wenn sich die Daten eines Knotens ändern, wird die Versionsnummer vom ZooKeeper-Dienst atomisch erhöht. Für Transaktionen mit mehreren Zeilen verwenden wir die multi-Methode, die serialisierbare Transaktionen über Siloknoten hinweg mit demselben übergeordneten Bereitstellungs-ID-Knoten garantiert.

  4. Consul IO: Wir haben den Schlüssel-Wert-Speicher von Consul verwendet, um die Mitgliedschaftstabelle zu implementieren. Weitere Informationen finden Sie unter Consul-Bereitstellung.

  5. AWS DynamoDB: In dieser Implementierung verwenden wir die Clusterbereitstellungs-ID als Partitionsschlüssel und die Siloidentität (ip-port-generation) als RangeKey (Bereichsschlüssel), der die Datensatzeinheit herstellt. Die optimistische Nebenläufigkeit wird durch das ETag-Attribut hergestellt, indem bedingte Schreibvorgänge in DynamoDB vorgenommen werden. Die Implementierungslogik ist der von Azure Table Storage sehr ähnlich.

  6. In-Memory-Emulation für das Entwicklungssetup. Für diese Implementierung verwenden wir ein spezielles System-Grain namens MembershipTableGrain. Dieses Grain existiert in einem bestimmten primären Silo, das nur für ein Entwicklungssetup verwendet wird. In jeder realen Produktionsnutzung ist eine Verwendung des primären Silos nicht erforderlich.

Konfiguration

Das Mitgliedschaftsprotokoll wird über das Liveness-Element im Abschnitt Globals in der Datei OrleansConfiguration.xml konfiguriert. Die Standardwerte wurden in Jahren der Produktionsnutzung in Azure optimiert, und wir sind der Meinung, dass sie gute Standardeinstellungen darstellen. Es besteht grundsätzlich keine Notwendigkeit, sie zu ändern.

Beispielkonfigurationselement:

<Liveness ProbeTimeout="5s"
    TableRefreshTimeout="10s"
    DeathVoteExpirationTimeout="80s"
    NumMissedProbesLimit="3"
    NumProbedSilos="3"
    NumVotesForDeathDeclaration="2" />

Es sind vier Arten von Aktivität („liveness“) implementiert. Der Typ des Aktivitätsprotokolls wird über das SystemStoreType-Attribut des SystemStore-Elements im Abschnitt Globals in der Datei OrleansConfiguration.xml konfiguriert.

  1. MembershipTableGrain: Die Mitgliedschaftstabelle wird in einem Grain im primären Silo gespeichert. Dies ist ausschließlich ein Entwicklungssetup.
  2. AzureTable: Die Mitgliedschaftstabelle wird in Azure Table gespeichert.
  3. SqlServer: Die Mitgliedschaftstabelle wird in einer relationalen Datenbank gespeichert.
  4. ZooKeeper: Die Mitgliedschaftstabelle wird in einem ZooKeeper-Ensemble gespeichert.
  5. Consul: Konfiguriert als benutzerdefinierter Systemspeicher mit MembershipTableAssembly = "OrleansConsulUtils". Weitere Informationen finden Sie unter Consul-Bereitstellung.
  6. DynamoDB: Konfiguriert als ein benutzerdefinierter Systemspeicher mit MembershipTableAssembly = "OrleansAWSUtils".

Für alle Aktivitätstypen sind die allgemeinen Konfigurationsvariablen im Globals.Liveness-Element definiert:

  1. ProbeTimeout: Die Anzahl der Sekunden, über die die Aktivität anderer Silos getestet werden soll, oder über die das Silo „I am Alive“-Heartbeatnachrichten über sich selbst senden soll. Der Standardwert ist 10 Sekunden.
  2. TableRefreshTimeout: Die Anzahl der Sekunden, über die Aktualisierungen aus der Mitgliedschaftstabelle abgerufen werden sollen. Der Standardwert ist 60 Sekunden.
  3. DeathVoteExpirationTimeout: Ablaufzeit in Sekunden für die Inaktivitätsabstimmung („death“) in der Mitgliedschaftstabelle. Der Standardwert ist 120 Sekunden.
  4. NumMissedProbesLimit: Die Anzahl der „I am alive“-Heartbeatnachrichten von einem Silo oder die Anzahl unbeantworteter Tests, die dazu führen, dass dieser Silo als inaktiv verdächtigt wird. Der Standardwert ist 3.
  5. NumProbedSilos: Die Anzahl der Silos, die von jedem Silo auf Aktivität getestet werden. Der Standardwert ist 3.
  6. NumVotesForDeathDeclaration: Die Anzahl der nicht abgelaufenen Abstimmungen, die erforderlich sind, um ein Silo für inaktiv zu erklären (sollte höchstens „NumMissedProbesLimit“ sein). Standard ist 2.
  7. UseLivenessGossip: Gibt an, ob die Gossip-Optimierung verwendet werden soll, um das Verbreiten von Aktivitätsinformationen zu beschleunigen. Der Standardwert ist "True".
  8. IAmAliveTablePublishTimeout: Die Anzahl der Sekunden, nach denen regelmäßig in die Mitgliedschaftstabelle geschrieben werden soll, dass dieses Silo aktiv ist. Wird nur für die Diagnose verwendet. Die Standardeinstellung ist 5 Minuten.
  9. NumMissedTableIAmAliveLimit: Die Anzahl der verpassten „I am alive“-Aktualisierungen von einem Silo in der Tabelle, was dazu führt, dass eine Warnung protokolliert wird. Hat keine Auswirkungen auf das Aktivitätsprotokoll. Standard ist 2.
  10. MaxJoinAttemptTime: Die Anzahl der Sekunden, über die versucht werden soll, einem Cluster von Silos beizutreten, bevor aufgegeben wird. Die Standardeinstellung ist 5 Minuten.
  11. ExpectedClusterSize: Die erwartete Größe eines Clusters. Muss nicht sehr genau sein, kann eine zu hohe Schätzung sein. Wird verwendet, um den exponentiellen Backoffalgorithmus für Wiederholungsversuche beim Schreiben in eine Azure Table zu optimieren. Der Standardwert ist 20.

Entwurfskonzept

Eine natürliche Frage, die sich stellen könnte, ist, warum man sich bei der Implementierung der Clustermitgliedschaft nicht vollständig auf Apache ZooKeeper verlässt, möglicherweise indem dessen sofort einsatzbereite Unterstützung für die Gruppenmitgliedschaft mit kurzlebigen Knoten verwendet wird? Warum haben wir uns die Mühe gemacht, unser Mitgliedschaftsprotokoll zu implementieren? Dafür gab es in erster Linie drei Gründe:

  1. Bereitstellung/Hosting in der Cloud:

    Zookeeper ist kein gehosteter Dienst (zumindest zum Zeitpunkt der Erstellung dieses Texts im Juli 2015 und definitiv bei der ersten Implementierung dieses Protokolls im Somme 2011 gab es keine Version von Zookeeper, die von einem wichtigen Cloudanbieter als gehosteter Dienst ausgeführt wurde). Dies bedeutet, dass Orleans-Kunden in der Cloudumgebung ihre Instanz eines ZK-Clusters bereitstellen/ausführen/verwalten müssten. Das ist nur eine weitere unnötige Belastung, die wir unseren Kunden nicht auferlegen wollten. Durch die Verwendung von Azure Table verlassen wir uns auf einen gehosteten, verwalteten Dienst, der das Leben unserer Kunden erheblich vereinfacht. Verwenden Sie in der Cloud die Cloud grundsätzlich als Plattform (aaP), nicht als Infrastruktur (aaI). Auf der anderen Seite, wenn Sie lokal ausführen und Ihre Server lokal verwalten, stellt die Verwendung von ZK als Implementierung der IMembershipTable eine praktikable Option dar.

  2. Direkte Fehlererkennung:

    Bei Verwendung der Gruppenmitgliedschaft von ZK mit kurzlebigen Knoten wird die Fehlererkennung zwischen den Orleans-Servern (ZK-Clients) und den ZK-Servern durchgeführt. Dies muss nicht unbedingt mit den tatsächlichen Netzwerkproblemen zwischen Orleans-Servern korrelieren. Unser Wunsch war es, dass die Fehlererkennung den clusterinternen Zustand der Kommunikation exakt widerspiegelt. Insbesondere gilt in unserem Entwurf ein IMembershipTable-Silo, wenn es nicht mit Orleans kommunizieren kann, nicht als inaktiv und kann weiter arbeiten. Im Gegensatz dazu kann bei Verwendung der ZK-Gruppenmitgliedschaft mit kurzlebigen Knoten eine Trennung von einem ZK-Server dazu führen, dass ein Orleans-Silo (ZK-Client) für inaktiv erklärt wird, während es noch aktiv und voll funktionsfähig ist.

  3. Portabilität und Flexibilität:

    Als Teil der Philosophie von Orleans wollen wir keine starke Abhängigkeit von einer bestimmten Technologie erzwingen, sondern setzen eher auf ein flexibles Design, bei dem verschiedene Komponenten mit unterschiedlichen Implementierungen leicht gewechselt werden können. Genau dies ist der Zweck, dem die IMembershipTable-Abstraktion dient.

Danksagung

Wir möchten Alex Kogan für seinen Beitrag zum Entwurf und zur Implementierung der ersten Version dieses Protokolls danken. Diese Arbeit wurde im Rahmen eines Sommerpraktikums bei Microsoft Research im Sommer 2011 durchgeführt. Die Implementierung der auf ZooKeeper basierenden IMembershipTable wurde von Shay Hazor durchgeführt, die Implementierung der SQL-IMembershipTable wurde von Veikko Eeva durchgeführt, die Implementierung der AWS DynamoDB-IMembershipTable wurde von Gutemberg Ribeiro durchgeführt, und die Implementierung der auf Consul basierenden IMembershipTable wurde von Paul North durchgeführt.