Модель размещения Azure Service Fabric

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

Прежде чем продолжить, убедитесь, что вы понимаете различные понятия и связи, описанные в статье Моделирование приложения в структуре службы.

Примечание

Если явно не указано иное, в этой статье:

  • Слово реплика относится к реплике службы с отслеживанием состояния или экземпляру службы без отслеживания состояния.
  • CodePackage считается эквивалентом процесса ServiceHost, который регистрирует ServiceType и размещает реплики служб этого ServiceType.

Чтобы понять модель размещения, давайте подробно рассмотрим пример. Допустим, мы имеем тип приложения MyAppType с типом службы MyServiceType, предоставляемым пакетом службы MyServicePackage с пакетом кода MyCodePackage, регистрирующим при запуске тип службы MyServiceType.

Допустим, мы имеем кластер из трех узлов и создаем приложениеfabric:/App1 типа MyAppType. Внутри этого приложения fabric:/App1 мы создаем службу fabric:/App1/ServiceA типа MyServiceType. Служба имеет 2 раздела (например, P1 и P2) с 3 репликами на каждый. На следующей схеме показано представление этого приложения, развернутого на узле.

Схема: представление этого приложения, развернутого на узле.

Service Fabric активирует пакет MyServicePackage, который запустил пакет MyCodePackage, где размещаются реплики из обоих разделов. Все узлы в кластере будут иметь одинаковое представление, так как мы выбрали число реплик на раздел, равное числу узлов в кластере. Теперь создадим другую службу, fabric:/App1/ServiceB, в приложении fabric:/App1. Служба имеет один раздел (например, P3) с тремя репликами. На следующей схеме показано новое представление узла:

Схема: новое представление на узле.

Service Fabric поместил новую реплику раздела P3 службы fabric:/App1/ServiceB в существующую активацию MyServicePackage. Теперь создадим другое приложение fabric:/App2 типа MyAppType. В приложении fabric:/App2 создадим службу fabric:/App2/ServiceA. Служба имеет 2 раздела (P4 и P5) с 3 репликами на каждый. На следующих схемах показано новое представление узла:

Схема: новое представление узла.

Service Fabric активирует новую копию пакета MyServicePackage, которая запускает новую копию пакета MyCodePackage. Реплики из обоих разделов службы fabric:/App2/ServiceA (например, P4 и P5) размещаются в этой новой копии MyCodePackage.

Модель с общим процессом

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

Модель с монопольным процессом

Другой моделью размещения, представляемой Service Fabric, является модель с монопольным процессом. В этой модели на заданном узле каждая реплика находится в отдельном выделенном процессе. Service Fabric активирует новую копию пакета ServicePackage (которая запускает все содержащиеся в ней пакеты CodePackage). Реплика размещается в CodePackage, который регистрирует ServiceType службы, к которой принадлежит реплика.

В Service Fabric, начиная с версии 5.6, модель с монопольным процессом можно выбрать во время создания службы (с помощью PowerShell, REST или FabricClient). Укажите для параметра ServicePackageActivationMode значение ExclusiveProcess.

PS C:\>New-ServiceFabricService -ApplicationName "fabric:/App1" -ServiceName "fabric:/App1/ServiceA" -ServiceTypeName "MyServiceType" -Stateless -PartitionSchemeSingleton -InstanceCount -1 -ServicePackageActivationMode "ExclusiveProcess"
var serviceDescription = new StatelessServiceDescription
{
    ApplicationName = new Uri("fabric:/App1"),
    ServiceName = new Uri("fabric:/App1/ServiceA"),
    ServiceTypeName = "MyServiceType",
    PartitionSchemeDescription = new SingletonPartitionSchemeDescription(),
    InstanceCount = -1,
    ServicePackageActivationMode = ServicePackageActivationMode.ExclusiveProcess
};

var fabricClient = new FabricClient(clusterEndpoints);
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);

Если в манифесте приложения указана служба по умолчанию, можно выбрать модель с монопольным процессом, указав атрибут ServicePackageActivationMode.

<DefaultServices>
  <Service Name="MyService" ServicePackageActivationMode="ExclusiveProcess">
    <StatelessService ServiceTypeName="MyServiceType" InstanceCount="1">
      <SingletonPartition/>
    </StatelessService>
  </Service>
</DefaultServices>

Теперь создадим другую службу, fabric:/App1/ServiceC, в приложении fabric:/App1. Служба имеет 2 раздела (например, P6 и P7) с 3 репликами на каждый. Укажите для параметра ServicePackageActivationMode значение ExclusiveProcess. На следующей схеме показано новое представление узла.

Схема представления узла развернутого приложения

Как видите, Service Fabric активировала две новые копии MyServicePackage (по одной на каждую реплику из раздела P6 иP7). Service Fabric размещает каждую реплику в выделенную копию CodePackage. При использовании модели с монопольным процессом для заданного приложения на узле могут быть активны несколько копий заданного ServicePackage. В предыдущем примере мы видим, что для fabric:/App1 активны три копии MyServicePackage. Каждая из этих активных копий MyServicePackage имеет связанный с ней ServicePackageAtivationId. Этот идентификатор определяет эту копию в приложении fabric:/App1.

Если для приложения используется только модель с общим процессом, на узле будет только одна активная копия ServicePackage. Значение ServicePackageAtivationId для этой активации ServicePackage будет соответствовать пустой строке. Так обстоит, к примеру, в случае с fabric:/App2.

Примечание

  • Модель размещения с общим процессом используется, когда для параметра ServicePackageActivationMode задано значение SharedProcess. Это модель размещения по умолчанию, поэтому во время создания службы необходимо указать значение ServicePackageActivationMode.

  • Модель размещения с монопольным процессом используется, когда для параметра ServicePackageActivationMode задано значение ExclusiveProcess. Чтобы использовать этот параметр, вы должны указать его явно во время создания службы.

  • Модель размещения службы можно узнать, запросив описание службы, где нужно просмотреть значение ServicePackageActivationMode.

Работа с развернутым пакетом службы

Активная копия ServicePackage на узле называется развернутым пакетом службы. Если при создании служб используется модель с монопольным процессом, для заданного приложения можно развернуть несколько пакетов служб одного пакета ServicePackage. Во время выполнения операций, относящихся к развернутому пакету службы, необходимо предоставить значение ServicePackageActivationId, позволяющее идентифицировать конкретный развернутый пакет службы. Например, для отправки сведений о работоспособности развернутого пакета службы или при перезапуске пакета кода развернутого пакета службы.

ServicePackageActivationId развернутого пакета службы можно получить, запросив список развернутых пакетов служб на узле. При запросе типов развернутых служб, реплик и пакетов кода на узле результат запроса также содержит значение ServicePackageActivationId родительского развернутого пакета службы.

Примечание

  • В модели размещения с общим процессом на заданном узле заданного приложения активируется только одна копия ServicePackage. При этом параметр ServicePackageActivationId соответствует пустой строке, и его не нужно указывать при выполнении операций, связанных с развернутым пакетом службы.

  • В модели размещения с монопольным процессом на заданном узле заданного приложения активируется одна или несколько копий ServicePackage. Каждая активация имеет непустое значение ServicePackageActivationId, указанное при выполнении операций, связанных с развернутым пакетом службы.

  • Если значение ServicePackageActivationId опущено, по умолчанию используется пустая строка. При наличии развернутого пакета службы, который был активирован с помощью модели с общим процессом, операция будет выполняться с ним. В противном случае операция завершится ошибкой.

  • Не выполняйте один запрос и не кэшируйте значение ServicePackageActivationId. Оно создается динамически и может изменяться по различным причинам. Перед выполнением операции, для которой требуется значение ServicePackageActivationId, сначала следует запросить список развернутых пакетов служб на узле. Затем используйте значение ServicePackageActivationId из результата запроса для выполнения исходной операции.

Гостевые исполняемые приложения и приложения-контейнеры

Service Fabric рассматривает гостевые исполняемые приложения и приложения-контейнеры как службы без отслеживания состояния, которые являются самодостаточными. Для них в процессе ServiceHost (в процессе или контейнере) нет среды выполнения Service Fabric. Так как эти службы являются самодостаточными, для этих служб число реплик на ServiceHost неприменимо. Самая распространенная конфигурация, которая используется с этими службами, — один раздел со значением InstanceCount равным -1 (с одной копией кода службы на каждом узле кластера).

По умолчанию параметр ServicePackageActivationMode этих служб имеет значение SharedProcess. В этом случае для заданного приложения Service Fabric активирует только одну копию ServicePackage на узле. Это означает, что на узле будет выполняться только одна копия кода службы. Если на узле требуется запустить несколько копий кода службы, во время создания службы для параметра ServicePackageActivationMode необходимо задать значение ExclusiveProcess. Например, при создании нескольких служб (от Service1 до ServiceN) типа ServiceType (указанного в ServiceManifest) или если служба имеет несколько разделов.

Изменение модели размещения существующей службы

В настоящее время вы не можете изменить модель размещения существующей службы с модели с общим процессом на модель с монопольным процессом (или наоборот).

Выбор между моделями размещения

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

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

Рекомендации по модели с монопольным процессом и модели приложения

Для моделирования большинства приложений в Service Fabric рекомендуется иметь один ServiceType для каждого ServicePackage.

Service Fabric предназначен для определенных вариантов использования и также позволяет использовать несколько значений ServiceType на значение ServicePackage (и одно значение CodePackage может зарегистрировать несколько значений ServiceType). Ниже приведены некоторые сценарии, в которых можно использовать эти конфигурации:

  • Необходимо оптимизировать использование ресурсов за счет запуска меньшего числа процессов с более высокой плотностью реплик для каждого из них.
  • Реплики различных ServiceType должны совместно использовать некоторые общие данные с высоким потреблением памяти или затратами на инициализацию.
  • У вас есть предложение с бесплатной службой, и вы хотите установить ограничение на использование ресурсов путем размещения всех реплик службы в один процесс.

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

Рассмотрим случай использования нескольких типов ServiceType для каждого ServicePackage, при котором каждый ServiceType регистрируется с помощью разных CodePackage. Предположим, мы имеем пакет ServicePackage MultiTypeServicePackage, который содержит два пакета CodePackage:

  • MyCodePackageA, который регистрирует тип службы MyServiceTypeA;
  • MyCodePackageB, который регистрирует тип службы MyServiceTypeB.

Теперь создадим приложение fabric:/SpecialApp. Внутри fabric:/SpecialApp создадим две следующие службы с помощью модели с монопольным процессом:

  • служба fabric:/SpecialApp/ServiceA типа MyServiceTypeA с двумя разделами (например, P1 и P2) и тремя репликами на каждый раздел;
  • служба fabric:/SpecialApp/ServiceB типа MyServiceTypeB с двумя разделами (например, P3 и P4) и тремя репликами на каждый раздел.

На заданном узле обе службы имеют две реплики. Так как для создания служб мы использовали модель с монопольным процессом, для каждой реплики Service Fabric активирует новую копию MyServicePackge. Каждая активация MultiTypeServicePackage запускает копию MyCodePackageA и MyCodePackageB. Однако только в одной из копий (MyCodePackageA или MyCodePackageB) размещена реплика, для которой был активирован MultiTypeServicePackage. На следующей схеме показано представление узла:

Схема: представление узла.

В активации MultiTypeServicePackage для реплики раздела P1 службы fabric:/SpecialApp/ServiceA в пакете MyCodePackageA размещается реплика. Пакет MyCodePackageB запущен и работает. Аналогично в активации MultiTypeServicePackage для реплики раздела P3 службы fabric:/SpecialApp/ServiceB в пакете MyCodePackageB размещается реплика. Пакет MyCodePackageА запущен и работает. Таким образом, чем больше количество пакетов CodePackage (регистрирующих различные типы ServiceType) для каждого ServicePackage, тем выше избыточное использование ресурсов.

Однако, если мы создадим службы fabric:/SpecialApp/ServiceA и fabric:/SpecialApp/ServiceB с помощью модели с общим процессом, Service Fabric активирует только одну копию MultiTypeServicePackage для приложения fabric:/SpecialApp. В пакете MyCodePackageA разместятся все реплики службы fabric:/SpecialApp/ServiceA. В пакете MyCodePackageВ разместятся все реплики службы fabric:/SpecialApp/ServiceВ. На следующей схеме показано представление узла в такой конфигурации:

Схема представления узла развернутого приложения

Из предыдущего примера можно сделать вывод, что если MyCodePackageA регистрирует оба типа MyServiceTypeA и MyServiceTypeB, но пакет MyCodePackageB отсутствует, избыточный CodePackage выполняться не будет. Хотя это верно, эта модель приложения не согласуется с моделью размещения с монопольным процессом. Если задача в том, чтобы разместить каждую реплику в свой собственный выделенный процесс, тогда регистрация обоих типов ServiceType из одного пакета CodePackage не требуется. Вместо этого проще поместить каждый ServiceType в свой собственный пакет ServicePackage.

Подпроцессы Reliable Services и "Разветвление субъекта"

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

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

Создайте пакет приложения и подготовьте его к развертыванию.

Развертывание и удаление приложений с помощью PowerShell. В статье представлены сведения об управлении экземплярами приложений с помощью PowerShell.