Поделиться через


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

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

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

Примечание.

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

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

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

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

Схема, показывающая, как это приложение выглядит в конечном виде на узле.

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. Этот сервис имеет два раздела (P4 и P5) и с тремя репликами на каждый раздел. На следующих схемах показано новое представление узла:

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

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. ServicePackageActivationId для этой активации 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). Ниже приведены некоторые сценарии, в которых можно использовать эти конфигурации:

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

Эксклюзивная модель размещения процессов не согласуется с моделью приложения, в которой несколько типов 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 активирует новую копию MyServicePackage. Каждая активация 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. В пакете MyCodePackageB размещаются все реплики службы fabric:/SpecialApp/ServiceB. На следующей схеме показано представление узла в такой конфигурации:

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

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

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

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

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

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

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