Стоимость перемещения служб

Фактор, который диспетчер кластерных ресурсов 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);

Вы также можете указать или обновить MoveCost динамически для службы после создания службы:

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);

Динамическое задание затрат на перемещение для каждой реплики

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

C#:

this.Partition.ReportMoveCost(MoveCost.Medium);

Примечание.

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

Отчет о затратах на перемещение раздела

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

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

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

Каждое обновление MoveCost для секции должно содержать по крайней мере одно допустимое значение, которое будет изменено. Например, вы можете пропустить обновление первичной реплики, назначив для ее записи значение null. Другие записи будут использоваться при обновлении MoveCost, и обновление MoveCost для первичной реплики будет пропущено. Так как обновление MoveCost для нескольких разделов с одним вызовом API возможно, API предоставляет список кодов возврата для соответствующей секции. Если мы успешно примем и обработаем запрос на обновление MoveCost, код возврата будет успех. В противном случае API предоставляет код ошибки:

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

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. Стоимость перемещения основной реплики будет Очень высокая. Стоимость перемещения всех вторичных реплик будет нулевой, за исключением стоимости перемещения для конкретной вторичной реплики, расположенной на узле NodeName0. Стоимость перемещения для конкретной реплики будет Средней. Если вы хотите пропустить обновление затрат на перемещение для первичной реплики или всех вторичных реплик, можно оставить соответствующую запись как null.

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

MoveCost имеет пять уровней: Ноль, Низкий, Средний, Высокий и Очень Высокий. Применяются следующие правила:

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

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

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

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

Это важно

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

Включение стоимости перемещения в вашем кластере

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

ClusterManifest.xml:

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

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

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

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