Share via


Reliable Services-Lebenszyklus

Reliable Services zählen zu den in Azure Service Fabric verfügbaren Programmiermodellen. Wenn Sie sich über den Lebenszyklus von Reliable Services informieren möchten, müssen Sie vor allem die grundlegenden Lebenszyklusereignisse verstehen. Die genaue Reihenfolge der Ereignisse hängt von Konfigurationsdetails ab.

Im Allgemeinen schließt der Reliable Services-Lebenszyklus die folgenden Ereignisse ein:

  • Während des Starts:
    • Dienste werden erstellt.
    • Dienste können keinen oder mehrere Listener erstellen und zurückgeben.
    • Alle zurückgegebenen Listener werden für die Kommunikation mit dem Dienst geöffnet.
    • Die runAsync-Methode des Diensts wird aufgerufen, sodass der Dienst langwierige Aufgaben oder Hintergrundarbeit ausführen kann.
  • Während des Herunterfahrens:
    • Das an runAsync übergebene Abbruchtoken wird abgebrochen, und die Listener werden geschlossen.
    • Das Dienstobjekt selbst wird zerstört.

Die Reihenfolge der Ereignisse in Reliable Services kann geringfügig abweichen, je nachdem, ob der zuverlässige Dienst zustandslos oder zustandsbehaftet ist.

Für zustandsbehaftete Dienste müssen Sie außerdem das Szenario mit Austausch des primären Replikats berücksichtigen. Während dieser Sequenz wird die Rolle des primären Replikats auf ein anderes Replikat (oder wieder zurück) übertragen, ohne dass der Dienst heruntergefahren wird.

Schließlich müssen Sie sich mit Fehlerbedingungen beschäftigen.

Start zustandsloser Dienste

Der Lebenszyklus eines zustandslosen Diensts ist recht einfach. So sieht die Reihenfolge der Ereignisse aus:

  1. Der Dienst wird erstellt.
  2. StatelessService.createServiceInstanceListeners() wird aufgerufen, und alle zurückgegebenen Listener werden geöffnet. CommunicationListener.openAsync() wird für jeden Listener aufgerufen.
  3. Anschließend findet parallele Ausführung statt:
    • Die runAsync-Methode des Diensts (StatelessService.runAsync()) wird aufgerufen.
    • Die eigene onOpenAsync-Methode des Diensts wird aufgerufen (sofern vorhanden). Insbesondere wird StatelessService.onOpenAsync() aufgerufen. Diese Außerkraftsetzung ist ungewöhnlich, aber verfügbar.

Herunterfahren zustandsloser Dienste

Beim Herunterfahren eines zustandslosen Diensts wird dasselbe Muster in umgekehrter Reihenfolge befolgt:

  1. Alle geöffneten Listener werden geschlossen. CommunicationListener.closeAsync() wird für jeden Listener aufgerufen.
  2. Das an runAsync() übergebene Abbruchtoken wird verworfen. Es wird überprüft, ob die isCancelled-Eigenschaft des Abbruchtokens true zurückgibt und ob die throwIfCancellationRequested-Methode eine Ausnahme vom Typ CancellationException auslöst.
  3. Nach Abschluss von runAsync() wird die StatelessService.onCloseAsync()-Methode des Diensts aufgerufen (sofern vorhanden). Auch hier handelt es sich nicht um eine gängige Überschreibung. Die Methode kann jedoch verwendet werden, um Ressourcen sicher zu schließen, die Hintergrundverarbeitung anzuhalten, das Speichern des externen Zustands zu beenden oder bestehende Verbindungen zu trennen.
  4. Nach Abschluss von StatelessService.onCloseAsync() wird das Dienstobjekt zerstört.

Start zustandsbehafteter Dienste

Zustandsbehaftete Dienste befolgen mit wenigen Änderungen ein ähnliches Muster wie zustandslose Dienste. Beim Starten eines zustandsbehafteten Diensts lautet die Reihenfolge der Ereignisse wie folgt:

  1. Der Dienst wird erstellt.
  2. StatefulServiceBase.onOpenAsync() wird aufgerufen. Dieser Aufruf wird normalerweise nicht im Dienst außer Kraft gesetzt.
  3. StatefulServiceBase.createServiceReplicaListeners() wird aufgerufen.
    • Wenn es sich bei dem Dienst um einen primären Dienst handelt, werden alle zurückgegebenen Listener geöffnet. CommunicationListener.openAsync() wird für jeden Listener aufgerufen.
    • Bei einem sekundären Dienst werden nur als listenOnSecondary = true gekennzeichnete Listener geöffnet. Für sekundäre Dienste geöffnete Listener sind eher selten.
  4. Anschließend findet parallele Ausführung statt:
    • Wenn es sich bei dem Dienst derzeit um einen primären Dienst handelt, wird die StatefulServiceBase.runAsync()-Methode des Diensts aufgerufen.
    • StatefulServiceBase.onChangeRoleAsync() wird aufgerufen. Dieser Aufruf wird normalerweise nicht im Dienst außer Kraft gesetzt.

Hinweis

Für ein neues sekundäres Replikat wird StatefulServiceBase.onChangeRoleAsync() zwei Mal aufgerufen. Ein Mal nach Schritt 2, wenn es zu einem sekundären Replikat im Leerlauf wird, und ein weiteres Mal während Schritt 4, wenn es zu einem aktiven sekundären Replikat wird. Weitere Informationen zu Replikaten und zum Instanzlebenszyklus finden Sie unter Replikate und Instanzlebenszyklus.

Herunterfahren zustandsbehafteter Dienste

Wie bei zustandslosen Diensten stimmen die Lebenszyklusereignisse während des Herunterfahrens mit denen während des Starts überein, aber in umgekehrter Reihenfolge. Wenn ein zustandsbehafteter Dienst heruntergefahren wird, treten die folgenden Ereignisse auf:

  1. Alle geöffneten Listener werden geschlossen. CommunicationListener.closeAsync() wird für jeden Listener aufgerufen.
  2. Das an runAsync() übergebene Abbruchtoken wird verworfen. Ein Aufruf der isCancelled()-Methode des Abbruchtokens gibt true zurück, und die throwIfCancellationRequested()-Methode des Tokens löst bei Aufruf eine Ausnahme vom Typ OperationCanceledException aus. Service Fabric wartet darauf, dass runAsync() abgeschlossen wird.

Hinweis

Ein Warten auf den Abschluss von runAsync ist nur erforderlich, wenn das Replikat ein primäres Replikat ist.

  1. Die Abschluss der runAsync()-Methode wird die StatefulServiceBase.onCloseAsync()-Methode des Diensts aufgerufen. Dieser Aufruf ist eine ungewöhnliche Außerkraftsetzung, aber verfügbar.
  2. Nach Abschluss von StatefulServiceBase.onCloseAsync() wird das Dienstobjekt zerstört.

Tausch des primären Replikats bei zustandsbehafteten Diensten

Während ein zustandsbehafteter Dienst ausgeführt wird, werden Kommunikationslistener geöffnet, und die runAsync-Methode wird nur für die primären Replikate dieses zustandsbehafteten Diensts aufgerufen. Die sekundären Replikate werden erstellt, erhalten jedoch keine weiteren Aufrufe. Während ein zustandsbehafteter Dienst ausgeführt wird, kann sich das Replikat ändern, das derzeit das primäre ist. Die für das zustandsbehaftete Replikat sichtbare Lebenszyklusereignisse sind davon abhängig, ob das Replikat während des Austauschs höher oder tiefer gestuft werden kann.

Tiefer gestuftes primäres Replikat

Das tiefer gestufte primäre Replikat muss für Service Fabric die Verarbeitung von Nachrichten und jegliche Hintergrundverarbeitung beenden. Dieser Schritt ist ähnlich dem Herunterfahren des Diensts. Ein Unterschied besteht darin, dass der Dienst nicht zerstört oder geschlossen wird, da er als sekundäres Replikat erhalten bleibt. Die folgenden Ereignisse treten auf:

  1. Alle geöffneten Listener werden geschlossen. CommunicationListener.closeAsync() wird für jeden Listener aufgerufen.
  2. Das an runAsync() übergebene Abbruchtoken wird verworfen. Eine Überprüfung der isCancelled()-Methode des Abbruchtokens gibt true zurück. Bei Aufruf löst die throwIfCancellationRequested()-Methode des Tokens eine Ausnahme vom Typ OperationCanceledException aus. Service Fabric wartet darauf, dass runAsync() abgeschlossen wird.
  3. Listener, die als „listenOnSecondary = true“ gekennzeichnet sind, werden geöffnet.
  4. Das StatefulServiceBase.onChangeRoleAsync()-Element des Diensts wird aufgerufen. Dieser Aufruf wird normalerweise nicht im Dienst außer Kraft gesetzt.

Höher gestuftes sekundäres Replikat

Analog dazu muss das höher gestufte sekundäre Replikat für Service Fabric mit dem Lauschen auf Nachrichten beginnen und alle Hintergrundaufgaben starten, die abgeschlossen werden müssen. Dieser Vorgang ähnelt dem Erstellen des Diensts. Der Unterschied besteht darin, dass das Replikat bereits vorhanden ist. Die folgenden Ereignisse treten auf:

  1. CommunicationListener.closeAsync() wird für alle geöffneten Listener aufgerufen (die mit „listenOnSecondary = true“ markiert sind)
  2. Alle Kommunikationslistener werden geöffnet. CommunicationListener.openAsync() wird für jeden Listener aufgerufen.
  3. Anschließend findet parallele Ausführung statt:
    • Die Methode StatefulServiceBase.runAsync() des Diensts wird aufgerufen.
    • StatefulServiceBase.onChangeRoleAsync() wird aufgerufen. Dieser Aufruf wird normalerweise nicht im Dienst außer Kraft gesetzt.

Hinweis

createServiceReplicaListeners wird nur ein einziges Mal aufgerufen und während der Replikathöherstufung oder -herabstufung nicht erneut aufgerufen. Dieselben ServiceReplicaListener-Instanzen werden verwendet, aber neue CommunicationListener-Instanzen werden erstellt (durch Aufrufen der ServiceReplicaListener.createCommunicationListener-Methode), nachdem die vorherigen Instanzen geschlossen wurden.

Allgemeine Probleme beim Herunterfahren zustandsbehafteter Dienste und beim Tieferstufen des primären Replikats

Service Fabric ändert das primäre Replikat eines zustandsbehafteten Diensts aus verschiedenen Gründen. Zu den gängigsten Gründen zählen Lastenausgleich im Cluster und Anwendungsupgrade. Während dieser Vorgänge ist es wichtig, dass der Dienst das cancellationToken berücksichtigt. Dies gilt auch während des normalen Herunterfahren des Diensts, z.B. wenn der Dienst gelöscht wurde.

Bei Diensten ohne ordnungsgemäße Abbruchbehandlung können mehrere Probleme auftreten. Diese Vorgänge werden verlangsamt, da Service Fabric auf eine ordnungsgemäße Beendigung der Dienste wartet. Dies kann letztendlich zu nicht erfolgreichen Upgrades mit Timeout und Rollback führen. Wenn das Abbruchtoken nicht berücksichtigt wird, können auch unausgeglichene Cluster entstehen. Cluster werden unausgeglichen, wenn Knoten stark ausgelastet sind. Die Dienste können jedoch nicht ausgeglichen werden, da ihre Verschiebung zu lange dauert.

Da es sich um zustandsbehaftete Dienste handelt, ist es auch wahrscheinlich, dass sie Reliable Collections verwenden. Beim Tieferstufen eines primären Replikats wird in Service Fabric als eine der ersten Maßnahmen der Schreibzugriff auf den zugrunde liegenden Zustand entzogen. Dies führt zu weiteren Problemen, die Einfluss auf den Lebenszyklus des Diensts haben können. Die Sammlungen geben Ausnahmen auf der Grundlage des Timings und abhängig davon zurück, ob das Replikat verschoben oder heruntergefahren wird. Diese Ausnahmen müssen ordnungsgemäß behandelt werden.

Von Service Fabric ausgelöste Ausnahmen sind permanent (FabricException) oder vorübergehend (FabricTransientException). Bei permanenten Ausnahmen sollte eine Ausnahme ausgelöst werden, und sie sollten protokolliert werden. Vorübergehende Ausnahmen können basierend auf Wiederholungslogik wiederholt werden.

Ein wichtiger Bestandteil der Tests und Prüfungen von Reliable Services ist die Behandlung von Ausnahmen, die auf die Verwendung von ReliableCollections in Verbindung mit Dienstlebenszyklusereignissen zurückzuführen sind. Es wird empfohlen, den Dienst immer unter Last auszuführen. Sie sollten vor der Bereitstellung in der Produktion auch Upgrades und Chaostests ausführen. Mit diesen einfachen Schritten können Sie sicherstellen, dass Ihr Dienst ordnungsgemäß implementiert ist und Lebenszyklusereignisse korrekt behandelt.

Hinweise zum Dienstlebenszyklus

  • Sowohl die runAsync()-Methode als auch die createServiceInstanceListeners/createServiceReplicaListeners-Aufrufe sind optional. Ein Dienst kann über eine dieser Varianten, beide oder keine von beiden verfügen. Wenn der Dienst beispielsweise alle Vorgänge infolge von Benutzeraufrufen ausführt, muss runAsync() nicht implementiert werden. Nur die Kommunikationslistener und der zugehörige Code sind erforderlich. Ebenso ist das Erstellen und Zurückgeben von Kommunikationsüberwachungen optional. Der Dienst muss möglicherweise nur Hintergrundverarbeitung ausführen, daher muss er nur runAsync() implementieren.
  • Ein Dienst kann runAsync() erfolgreich abschließen und dann zurückkehren. Dies wird nicht als Fehlerbedingung angesehen. Es stellt die Hintergrundverarbeitung des Diensts während des Abschlusses dar. Für zustandsbehaftete Reliable Services wird runAsync() erneut aufgerufen, wenn der Dienst vom primären Replikat tiefer gestuft und dann wieder auf das primäre Replikat höher gestuft wird.
  • Wenn ein Dienst die Ausführung von runAsync() mit einer unerwarteten Ausnahme beendet, ist dies ein Fehler. Das Dienstobjekt wird heruntergefahren, und ein Integritätsfehler wird gemeldet.
  • Zwar gibt es keine zeitliche Begrenzung für die Rückkehr von diesen Methoden, Sie verlieren jedoch sofort die Möglichkeit zum Schreiben. Daher können Sie Ihre eigentlichen Arbeiten nicht abschließen. Es wird empfohlen, sie so schnell wie möglich nach dem Empfang der Abbruchanforderung zurückzugeben. Wenn der Dienst nicht in einem angemessenen Zeitraum auf diese API-Aufrufe reagiert, kann Service Fabric das Beenden des Diensts erzwingen. Dies geschieht normalerweise nur während Anwendungsupgrades oder beim Löschen eines Diensts. Das Timeout beträgt standardmäßig 15 Minuten.
  • Fehler im onCloseAsync()-Pfad führen zu einem Aufruf von onAbort(). Dadurch erhält der Dienst eine letzte Gelegenheit zum Bereinigen und Freigeben aller beanspruchten Ressourcen. Diese Methode wird im Allgemeinen verwendet, wenn auf dem Knoten ein dauerhafter Fehler erkannt wird oder Service Fabric den Lebenszyklus der Dienstinstanz aufgrund von internen Fehlern nicht zuverlässig verwalten kann.
  • OnChangeRoleAsync() wird immer dann aufgerufen, wenn das Replikat des zustandsbehafteten Diensts die Rolle wechselt und beispielsweise ein primäres oder sekundäres Replikat wird. Primäre Replikate erhalten Schreibstatus (mit Erlaubnis zum Erstellen und Schreiben in Reliable Collections). Sekundäre Replikate erhalten Lesestatus (können nur aus vorhandenen Reliable Collections lesen). Die meisten Aufgaben in einem zustandsbehafteten Dienst werden im primären Replikat ausgeführt. Sekundäre Replikate können schreibgeschützte Überprüfungen durchführen, Berichte generieren und Data Mining oder andere schreibgeschützte Aufträge ausführen.

Nächste Schritte