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.
- Das an
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:
- Der Dienst wird erstellt.
StatelessService.createServiceInstanceListeners()
wird aufgerufen, und alle zurückgegebenen Listener werden geöffnet.CommunicationListener.openAsync()
wird für jeden Listener aufgerufen.- 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 wirdStatelessService.onOpenAsync()
aufgerufen. Diese Außerkraftsetzung ist ungewöhnlich, aber verfügbar.
- Die
Herunterfahren zustandsloser Dienste
Beim Herunterfahren eines zustandslosen Diensts wird dasselbe Muster in umgekehrter Reihenfolge befolgt:
- Alle geöffneten Listener werden geschlossen.
CommunicationListener.closeAsync()
wird für jeden Listener aufgerufen. - Das an
runAsync()
übergebene Abbruchtoken wird verworfen. Es wird überprüft, ob dieisCancelled
-Eigenschaft des Abbruchtokenstrue
zurückgibt und ob diethrowIfCancellationRequested
-Methode eine Ausnahme vom TypCancellationException
auslöst. - Nach Abschluss von
runAsync()
wird dieStatelessService.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. - 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:
- Der Dienst wird erstellt.
StatefulServiceBase.onOpenAsync()
wird aufgerufen. Dieser Aufruf wird normalerweise nicht im Dienst außer Kraft gesetzt.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.
- Wenn es sich bei dem Dienst um einen primären Dienst handelt, werden alle zurückgegebenen Listener geöffnet.
- 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.
- Wenn es sich bei dem Dienst derzeit um einen primären Dienst handelt, wird die
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:
- Alle geöffneten Listener werden geschlossen.
CommunicationListener.closeAsync()
wird für jeden Listener aufgerufen. - Das an
runAsync()
übergebene Abbruchtoken wird verworfen. Ein Aufruf derisCancelled()
-Methode des Abbruchtokens gibttrue
zurück, und diethrowIfCancellationRequested()
-Methode des Tokens löst bei Aufruf eine Ausnahme vom TypOperationCanceledException
aus. Service Fabric wartet darauf, dassrunAsync()
abgeschlossen wird.
Hinweis
Ein Warten auf den Abschluss von runAsync
ist nur erforderlich, wenn das Replikat ein primäres Replikat ist.
- Die Abschluss der
runAsync()
-Methode wird dieStatefulServiceBase.onCloseAsync()
-Methode des Diensts aufgerufen. Dieser Aufruf ist eine ungewöhnliche Außerkraftsetzung, aber verfügbar. - 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:
- Alle geöffneten Listener werden geschlossen.
CommunicationListener.closeAsync()
wird für jeden Listener aufgerufen. - Das an
runAsync()
übergebene Abbruchtoken wird verworfen. Eine Überprüfung derisCancelled()
-Methode des Abbruchtokens gibttrue
zurück. Bei Aufruf löst diethrowIfCancellationRequested()
-Methode des Tokens eine Ausnahme vom TypOperationCanceledException
aus. Service Fabric wartet darauf, dassrunAsync()
abgeschlossen wird. - Listener, die als „listenOnSecondary = true“ gekennzeichnet sind, werden geöffnet.
- 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:
CommunicationListener.closeAsync()
wird für alle geöffneten Listener aufgerufen (die mit „listenOnSecondary = true“ markiert sind)- Alle Kommunikationslistener werden geöffnet.
CommunicationListener.openAsync()
wird für jeden Listener aufgerufen. - 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.
- Die Methode
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 diecreateServiceInstanceListeners/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, mussrunAsync()
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 nurrunAsync()
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 wirdrunAsync()
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 vononAbort()
. 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.