Жизненный цикл Reliable Services

Если речь идет о жизненных циклах служб Reliable Services в Azure Service Fabric, наиболее важны основные аспекты. Как правило, жизненный цикл состоит из следующих этапов.

  • Во время запуска:
    • создаются службы;
    • службы могут создавать и возвращать ни одного или несколько прослушивателей;
    • все возвращаемые прослушиватели открываются, что разрешает взаимодействовать со службой;
    • вызывается метод RunAsync службы, позволяя службе выполнять длительные задания или фоновую работу.
  • Во время завершения работы:
    • токен отмены, переданный в RunAsync, отменяется и прослушиватели закрываются;
    • после этого уничтожается сам объект службы.

Следует отметить некоторые моменты, связанные с точным порядком этих событий. Порядок событий может немного изменяться в зависимости от того, предусматривают ли Reliable Services отслеживание состояния. В случае со службами с отслеживанием состояния нужно иметь дело со сценарием переключения первичной реплики. Во время этой процедуры первичная роль передается другой реплике (или возвращается) без завершения работы службы. И, наконец, необходимо учитывать условия ошибок и сбоев.

Запуск службы без отслеживания состояния

Жизненный цикл службы без отслеживания состояния прост. Ниже приведен порядок событий.

  1. Создается служба.
  2. Вызывается метод StatelessService.CreateServiceInstanceListeners() и открываются все возвращаемые прослушиватели. Для каждого прослушивателя вызывается метод ICommunicationListener.OpenAsync().
  3. Затем одновременно происходят две вещи.
    • Вызывается метод службы StatelessService.RunAsync().
    • Вызывается метод StatelessService.OnOpenAsync() службы, если он присутствует. Этот вызов представляет собой редко используемое переопределение, но оно доступно. В этот момент можно запустить расширенные задачи инициализации службы.

Завершение работы службы без отслеживания состояния

Для завершения работы службы без отслеживания состояния те же операции выполняются в обратном порядке.

  1. Закрываются все открытые прослушиватели. Для каждого прослушивателя вызывается метод ICommunicationListener.CloseAsync().
  2. Токен отмены, переданный в RunAsync(), отменяется. В результате проверки свойства IsCancellationRequested токена отмены возвращается значение true, а при вызове метода ThrowIfCancellationRequested маркера возвращается OperationCanceledException. Service Fabric ожидает завершения RunAsync().
  3. После завершения RunAsync() вызывается метод StatelessService.OnCloseAsync() службы, если он присутствует. OnCloseAsync вызывается, когда работу экземпляра службы без отслеживания состояния планируется корректно завершить. Это может произойти при обновлении кода службы, перемещении экземпляра службы в целях балансировки нагрузки или при обнаружении временной ошибки. Обычно StatelessService.OnCloseAsync() не переопределяется, но позволяет безопасно закрыть все ресурсы, остановить все фоновые задачи, завершить сохранение внешнего состояния или закрыть существующие подключения.
  4. После выполнения метода StatelessService.OnCloseAsync() объект службы уничтожается.

Запуск службы с отслеживанием состояния

Запуск службы с отслеживанием состояния имеет лишь несколько отличий по сравнению со службой без отслеживания состояния. Для запуска службы с отслеживанием состояния порядок событий выглядит следующим образом:

  1. Создается служба.

  2. Вызывается метод StatefulServiceBase.OnOpenAsync(). Этот вызов редко переопределяется в службе.

  3. Вызывается метод StatefulServiceBase.CreateServiceReplicaListeners().

    • Если служба является первичной, открываются все возвращенные прослушиватели. Для каждого прослушивателя вызывается метод ICommunicationListener.OpenAsync().
    • Если служба является вторичной, то открываются только прослушиватели, помеченные как ListenOnSecondary = true. Открытые прослушиватели для вторичных служб используются реже.
  4. Затем параллельно:

    • Если сейчас служба является первичной, то вызывается метод StatefulServiceBase.RunAsync().
    • Вызывается метод StatefulServiceBase.OnChangeRoleAsync(). Этот вызов редко переопределяется в службе.

    Примечание

    Для новой вторичной реплики StatefulServiceBase.OnChangeRoleAsync() вызывается дважды: после шага 2, когда он получает статус "Дополнительный в режиме простоя", и еще раз во время шага 4, когда он получает статус "Дополнительный активный". Дополнительные сведения о жизненном цикле реплики и экземпляра см. в статье Жизненный цикл реплики и экземпляра.

Завершение работы службы с отслеживанием состояния

Как и в случае со службами без отслеживания состояния, события жизненного цикла во время завершения работы совпадают с событиями во время запуска, но происходят в обратном порядке. При завершении работы службы с отслеживанием состояния происходят следующие события.

  1. Закрываются все открытые прослушиватели. Для каждого прослушивателя вызывается метод ICommunicationListener.CloseAsync().

  2. Вызывается метод StatefulServiceBase.OnCloseAsync(). Этот вызов представляет собой редко используемое переопределение, но оно доступно.

  3. Токен отмены, переданный в RunAsync(), отменяется. В результате проверки свойства IsCancellationRequested токена отмены возвращается значение true, а при вызове метода ThrowIfCancellationRequested маркера возвращается OperationCanceledException. Service Fabric ожидает завершения RunAsync().

    Примечание

    Если это первичная реплика, необходимо подождать завершения RunAsync.

  4. После выполнения метода StatefulServiceBase.RunAsync() объект службы уничтожается.

Переключения первичной реплики службы с отслеживанием состояния

Во время выполнения службы с отслеживанием состояния только первичные реплики этих служб открывают прослушиватели связи и вызывают метод RunAsync. Вторичные реплики создаются, но не видят последующие вызовы. Пока выполняется служба с отслеживанием состояния, первичная реплика может измениться в результате сбоя или оптимизации балансировки кластера. Что это означает с точки зрения событий жизненного цикла, которые может видеть реплика? Поведение, которое видит реплика с отслеживанием состояния, зависит от того, что происходит во время переключения: понижение или повышение реплики.

При пониженной первичной реплике

Для пониженной первичной реплики Service Fabric требуется, чтобы эта реплика остановила обработку сообщений и выполнение любой фоновой работы. Это выглядит аналогично завершению работы службы. Отличие в том, что служба не уничтожается и не закрывается, так как остается вторичной. Вызываются следующие API.

  1. Закрываются все открытые прослушиватели. Для каждого прослушивателя вызывается метод ICommunicationListener.CloseAsync().
  2. Токен отмены, переданный в RunAsync(), отменяется. В результате проверки свойства IsCancellationRequested токена отмены возвращается значение true, а при вызове метода ThrowIfCancellationRequested маркера возвращается OperationCanceledException. Service Fabric ожидает завершения RunAsync().
  3. Открываются прослушиватели, имеющие свойство ListenOnSecondary = true.
  4. Вызывается служба StatefulServiceBase.OnChangeRoleAsync(). Этот вызов редко переопределяется в службе.

При повышении уровня вторичной реплики

Аналогичным образом Service Fabric необходимо, чтобы вторичная реплика с повышенным уровнем начала ожидать передачи сообщений и запустила все фоновые задачи, которые необходимо выполнить. Эта процедура соответствует процессу создания службы за исключением того, что сама реплика уже существует. Вызываются следующие API.

  1. ICommunicationListener.CloseAsync() вызывается для всех открытых прослушивателей (имеющих свойство ListenOnSecondary = true).
  2. Открываются все прослушиватели связи. Для каждого прослушивателя вызывается метод ICommunicationListener.OpenAsync().
  3. Затем параллельно:
    • Вызывается метод службы StatefulServiceBase.RunAsync().
    • Вызывается метод StatefulServiceBase.OnChangeRoleAsync(). Этот вызов редко переопределяется в службе.

Примечание

CreateServiceReplicaListeners вызывается только один раз и не вызывается повторно в процессе повышения или понижения уровня реплики; используются те же экземпляры ServiceReplicaListener, но при этом создаются новые экземпляры ICommunicationListener (путем вызова метода ServiceReplicaListener.CreateCommunicationListener) после закрытия предыдущих экземпляров.

Распространенные проблемы во время завершения работы службы с отслеживанием состояния и понижения уровня первичной реплики

Service Fabric изменяет первичную реплику службы с отслеживанием состояния по ряду причин. Наиболее распространенными являются балансировка кластера и обновление приложения. Во время этих операций (а также во время штатного завершения работы службы, т. е. как при ее удалении) очень важно, чтобы служба учитывала CancellationToken.

Службы, которые не обрабатывают отмену аккуратно, могут вызывать несколько проблем. Эти операции выполняются медленно, так как Service Fabric ожидает корректную остановку служб. В конечном счете это может привести к сбоям обновлений из-за истечения времени ожидания и откату. Если не использовать токен отмены, это может также нарушить балансировку кластеров. Кластеры становятся несбалансированными, потому что узлы нагружаются, но реорганизация служб невозможна, так как их перемещение занимает слишком много времени.

Так как это службы с отслеживанием состояния, то, скорее всего, они используют надежные коллекции. Когда в Service Fabric понижается уровень первичной реплики, то в первую очередь отменяется доступ на запись к базовому состоянию. Это приводит ко второму ряду проблем, которые могут повлиять на жизненный цикл службы. Коллекции возвращают исключения на основании времени и операции с репликой (перемещение или завершение работы). Эти исключения должны обрабатываться правильно. Исключения, порождаемые Service Fabric, делятся на постоянные (FabricException) и временные (FabricTransientException). Постоянные исключения должны быть зарегистрированы в журнале и порождены, тогда как для временных исключений возможен повтор породившей их операции в соответствии с логикой повтора.

Обработка исключений, которые поступают от ReliableCollections, в сочетании с событиями жизненного цикла службы является важной частью тестирования и проверки надежной службы. Перед развертыванием в рабочей среде рекомендуется запустить службу под нагрузкой во время выполнения обновлений и хаотического тестирования. Эти простые действия помогут обеспечить правильную реализацию службы и обработку событий жизненного цикла.

Примечания о жизненном цикле службы

  • Метод RunAsync() и вызовы CreateServiceReplicaListeners/CreateServiceInstanceListeners являются необязательны. В службе может использоваться один из них, оба или ни одного. Например, если служба выполняет всю работу в ответ на вызовы пользователя, реализовывать метод RunAsync() не нужно. Необходимы только прослушиватели связи и соответствующий код. Создание и возвращение прослушивателей связи является необязательным, так как у службы может быть только фоновая работа, поэтому достаточно реализовать RunAsync().
  • Служба может успешно завершить RunAsync() и вернуться из него. Завершение не является состоянием сбоя. Завершение RunAsync() указывает на то, что фоновая работа службы выполнена. Для надежных служб с отслеживанием состояния RunAsync() вызывается снова, если уровень реплики понижен с первичной до вторичной, а затем обратно повышен до первичной.
  • Если служба выполняет выход из RunAsync(), порождая какое-либо непредвиденное исключение, это означает сбой. Объект службы завершает работу и появляется ошибка о работоспособности.
  • Несмотря на то, что возвращение этих методов не ограничивается по времени, вы не сможете записать никакие надежные коллекции, а значит, и выполнить какую-либо действительную задачу. После получения запроса на отмену рекомендуется возвращать методы как можно быстрее. Если служба не отвечает на такие вызовы API в течение приемлемого промежутка времени, Service Fabric может принудительно завершить работу службы. Обычно это происходит только во время обновления приложения или при удалении службы. По умолчанию время ожидания составляет 15 минут.
  • Сбои в пути OnCloseAsync() приводят к вызову OnAbort(), что является последней наилучшей возможностью для службы очистить и освободить все запрошенные ресурсы. Обычно такой вызов осуществляется при обнаружении на узле постоянной неисправности или когда платформа Service Fabric не может надежно управлять жизненным циклом экземпляра службы из-за внутренних сбоев.
  • OnChangeRoleAsync() вызывается, когда реплика службы с отслеживанием состояния меняет роль, например с первичной на вторичную, или наоборот. Основным репликам присваивается статус записи (им разрешено создавать и записывать надежные коллекции), а дополнительным — статус чтения (могут только читать из существующих надежных коллекций). Большинство операций службы с отслеживанием состояния выполняется в основной реплике. Вторичные реплики могут выполнять проверку, предусматривающую только чтение, создавать отчеты, выполнять интеллектуальный анализ данных, а также другие задания, доступные только для чтения.

Дальнейшие действия