Затраты на перемещение служб

Фактором, который диспетчер кластерных ресурсов Service Fabric принимает во внимание при попытке определить, какие изменения вносить в кластер, являются общие затраты на эти изменения. Понятие "затраты" соотносится со степенью улучшения кластера. Затраты учитываются при перемещении служб для балансировки, дефрагментации и выполнения других требований. Цель — выполнить требования с наименьшим вмешательством или затратами.

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

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

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

Настройка затрат на перемещение

Можно задать затраты на перемещение по умолчанию для службы при ее создании.

PowerShell.

New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceTypeName –Stateful -MinReplicaSetSize 3 -TargetReplicaSetSize 3 -PartitionSchemeSingleton -DefaultMoveCost Medium

C#:

FabricClient fabricClient = new FabricClient();
StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
//set up the rest of the ServiceDescription
serviceDescription.DefaultMoveCost = MoveCost.Medium;
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);

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

PowerShell.

Update-ServiceFabricService -Stateful -ServiceName "fabric:/AppName/ServiceName" -DefaultMoveCost High

C#:

StatefulServiceUpdateDescription updateDescription = new StatefulServiceUpdateDescription();
updateDescription.DefaultMoveCost = MoveCost.High;
await fabricClient.ServiceManager.UpdateServiceAsync(new Uri("fabric:/AppName/ServiceName"), updateDescription);

Динамическое указание затрат на перемещение на уровне реплики

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

C#:

this.Partition.ReportMoveCost(MoveCost.Medium);

Примечание

Стоимость перемещения для вторичных реплик можно задать только с помощью кода.

Отчеты о затратах на перемещение секции

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

Вы можете передавать обновления стоимости перемещения для разных разделов в одном вызове API. Для каждого раздела, в котором вы хотите сохранить новое значение стоимости перемещения, нужно указать объект PartitionMoveCostDescription,. Этот API позволяет обновлять стоимость перемещения несколькими способами.

  • Раздел службы с отслеживанием состояния может обновлять сведения о стоимости перемещения для своей первичной реплики.
  • Службы с отслеживанием и без отслеживания состояния могут обновлять стоимость перемещения для всех своих вторичных реплик или экземпляров.
  • Службы с отслеживанием и без отслеживания состояния могут обновлять стоимость перемещения для конкретной реплики или экземпляра на узле.

Каждое обновление стоимости перемещения для секции должно содержать по крайней мере одно допустимое значение, которое будет изменено. Например, можно пропустить обновление первичной реплики, присвоив значение NULL записи первичной реплики. В этом случае во время обновления стоимости перемещения будут использоваться другие записи, а обновление стоимости перемещения для первичной реплики будет пропущено. Поскольку поддерживается обновление стоимости перемещения для нескольких разделов в одном вызове API, API возвращает список кодов возврата для каждого раздела. Если запрос на обновление стоимости перемещения был успешно принят и обработан, возвращается код Success (Успешно). В противном случае API предоставляет код ошибки:

  • PartitionNotFound — указанный идентификатор раздела не существует.
  • ReconfigurationPending — раздел в настоящее время перестраивается.
  • InvalidForStatelessServices — была предпринята попытка изменить стоимость перемещения первичной реплики для раздела, принадлежащего службе без отслеживания состояния.
  • ReplicaDoesNotExist — вторичная реплика или экземпляр не существует на указанном узле.
  • InvalidOperation — обновление стоимости перемещения для раздела, принадлежащего системному приложению.

C#:

Guid partitionId = Guid.Parse("53df3d7f-5471-403b-b736-bde6ad584f42");
string nodeName0 = "NodeName0";

OperationResult<UpdatePartitionMoveCostResultList> updatePartitionMoveCostResults =
    await this.FabricClient.UpdatePartitionMoveCostAsync(
        new UpdatePartitionMoveCostQueryDescription
        {
            new List<PartitionMoveCostDescription>()
            {
                new PartitionMoveCostDescription(
                    partitionId,
                    MoveCost.VeryHigh,
                    MoveCost.Zero,
                    new List<ReplicaMoveCostDescription>()
                    {
                        new ReplicaMoveCostDescription(nodeName0, MoveCost.Medium)
                    })
            }
        },
        this.Timeout,
        cancellationToken);

В этом примере вы выполните обновление последней зарегистрированной стоимости перемещения для раздела 53df3d7f-5471-403b-b736-bde6ad584f42. Стоимость перемещения первичной реплики будет иметь значение VeryHigh (Очень большая). Стоимость перемещения всех вторичных реплик будет Zero (Нуль), за исключением затрат на перемещение определенной вторичной реплики, расположенной на узле NodeName0. Затраты на перемещение для определенной реплики будут Medium (Средние). Если вы хотите пропустить обновление стоимости перемещения для первичной реплики или всех вторичных реплик, можно сохранить для соответствующей записи значение NULL.

Влияние затрат на перемещение

У затрат на перемещение есть пять уровней: Zero (нулевой), Low (низкий), Medium (средний), High (высокий) и VeryHigh (очень высокий). Применяются следующие правила.

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

Стоимость перемещения как фактор выбора реплик для перемещения

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

  • Объем данных состояния или информации, перемещаемой для службы.
  • Стоимость отключения клиентов. Как правило, затраты на перемещение первичной реплики выше, чем затраты на перемещение вторичной реплики.
  • Стоимость прерывания текущих операций. Некоторые операции уровня хранилища данных или операции, выполняемые по вызову клиента, являются дорогостоящими. После определенного момента вы не станете останавливать их, если только это не вынужденная мера. Поэтому пока происходит операция, увеличьте стоимость перемещения этого объекта службы, чтобы снизить вероятность его перемещения. А после завершения операции восстановите обычное значение стоимости перемещения.

Важно!

Использование стоимости перемещения VeryHigh следует тщательно обдумать, так как этот вариант существенно ограничивает способность Диспетчера кластерных ресурсов находить глобально оптимальное решение для размещения в кластере. Реплики с затратами на перемещение VeryHigh перемещаются только в том случае, если в кластере нарушается ограничение, которое не может быть исправлено каким-либо другим способом, в том числе путем перемещения многих других реплик.

Включение учета затрат на перемещение в кластере

Чтобы обеспечить учет более детализированных затрат на перемещение, в кластере нужно включить использование затрат на перемещение. Если это не настроить, то для расчета затрат на перемещение используется стандартный режим подсчета перемещений и отчеты о затратах на перемещение игнорируются.

ClusterManifest.xml:

        <Section Name="PlacementAndLoadBalancing">
            <Parameter Name="UseMoveCostReports" Value="true" />
        </Section>

Для автономных развертываний используется ClusterConfig.json, а для размещенных в Azure кластеров — Template.json.

"fabricSettings": [
  {
    "name": "PlacementAndLoadBalancing",
    "parameters": [
      {
          "name": "UseMoveCostReports",
          "value": "true"
      }
    ]
  }
]

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