Интегральные гарантии

Базовый механизм предоставления гарантий на вычислительные ресурсы в системе YTsaurus предполагает выдачу константного количества ресурсов (строгая гарантия), выраженного чаще всего в ядрах CPU. Такой вид гарантии хорошо подходит для задач, способных постоянно утилизировать ресурсы. В реальности встречаются и другие сценарии, в которых требуется бо́льшая гибкость.

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

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

Механизм интегральных гарантий позволяет найти баланс между описанными сценариями.

Интегральные пулы

В системе YTsaurus существует возможность включить накопление ресурсов для пула. В такие пулы с постоянной скоростью поступает некоторый объём виртуальных ресурсов — accumulated_resource_ratio_volume. Объём ресурса хранится в доле кластера в секунду — fair_share*sec, но для простоты можно считать, что значение приведено в ядрах в секунду — cpu*sec. Пул может расходовать виртуальный ресурс, чтобы запускать операции, а может накапливать его до определённого лимита.

Пример: пусть в пуле накопилось accumulated_resource_ratio_volume = 60 fair_share*sec, на кластере 1000 ядер, и доминантный ресурс пользовательского процесса — CPU. Данный объём можно пересчитать в ядра * секунды60000 cpu*sec. Операция, потребляющая в моменте 100 CPU, истратит данный объём за 10 минут, а потребляющая 50 CPU — за 20 минут. В данном примере не учитывается, что с течением времени объём виртуального ресурса в пуле пополняется.

Скорость накопления ресурса настраивается в атрибуте пула integral-guarantees/resource_flow. В значении атрибута должен быть указан тип ресурса и его объём:

$ yt set //sys/pools/root-pool/burst/@integral-guarantees/resource_flow "{cpu=100}"

Поскольку resource_flow — это скорость увеличения accumulated_resource_ratio_volume, который представляет собой мгновенное количество ресурса умноженное на время, то resource_flow/cpu измеряется в ядрах, проще говоря, cpu*sec/sec = cpu. Например, resource_flow/cpu = 100 позволяет бесконечно долго выполняться операции, потребляющей 100 CPU в моменте.

Накопление accumulated_resource_ratio_volume происходит до определённого предела, который равен k*resource_flow_ratio, где k — единый для всех пулов параметр планировщика, а resource_flow_ratioresource_flow как доля от всех ресурсов кластера. Значение для параметра k настраивается администратором кластера.

Описанная идея накопления и расходования ресурсов во многом похожа на алгоритм Token bucket. Не стоит путать с Leaky bucket.

Виды гарантий

В системе YTsaurus существует три вида гарантий на вычислительные ресурсы:

  • strong_guarantee — строгая гарантия доли ресурсов кластера. Выставляется в том числе в абсолютном значении (в ядрах), автоматически пересчитывается в долю кластера. Позволяет в любой момент времени получить гарантию и использовать её бесконечно долго;
  • burst_integral — гарантия в моменте («пиковая гарантия») в ядрах, позволяет получать фиксированную гарантию в течение промежутка времени. Например, получать 2000 ядер в течение двух часов в сутки;
  • relaxed_integral — интегральная гарантия (в ядрах) позволяет получить фиксированный объём ресурса в среднем за сутки.

Типы интегральных пулов

Для поддержки двух сценариев, описанных в начале раздела, в системе YTsaurus реализованы два типа интегральных пулов:

  • Burst pool — пул, который имеет приоритет при расходовании accumulated_resource_ratio_volume. У таких пулов должны быть указаны resource_flow и burst_guarantee_resources. При наличии операций в пуле, требующих ресурсов (demand), планировщик обязан выдать не менее burst_guarantee_resources пулу, если в пуле накоплено достаточно accumulated_resource_ratio_volume. Данный тип пулов обеспечивает burst_integral гарантию.

    Пример конфигурации burst пула:

    yt set //sys/pools/root-pool/burst/@integral-guarantees "
    {
      guarantee_type=burst;
      resource_flow={cpu=1000};
      burst_guarantee_resources={cpu=2000}
    }"
    

    В приведённом примере пользователь может рассчитывать, что пулу гарантированы 1000 ядер всегда или 2000 "половину" времени (например, 12 часов в сутки), если в течение второй половины ничего не запускается.

    Burst гарантия одновременно является и ограничением скорости потребления накопленного ресурса. Если гарантия burst_gurantee_resources/cpu равна 2000, то по умолчанию планировщик не даст пулу потребить более 2000 ядер в моменте. Такое поведение обеспечивает защиту от случайного быстрого расходования накопленного интегрального ресурса.

  • Relaxed pool — пул, для которого нет гарантии получить все ресурсы за accumulated_resource_ratio_volume в заданный момент, но есть гарантия получить их в итоге (в течение суток). Для relaxed пула можно задать только resource_flow. Предполагается, что в таких пулах будут запускаться операции, которые не требуют мгновенного получения ресурсов, которые им полагаются. Данный тип пулов обеспечивает relaxed_integral гарантию.
    Пример конфигурации relaxed пула:

    Листинг 3

    yt set //sys/pools/root-pool/relaxed/@integral-guarantees "
    {
      guarantee_type=relaxed;
      resource_flow={cpu=1000}
    }"
    

    В relaxed пулах, также как и в burst пулах, существует ограничение на потребление ресурсов. В случае relaxed пулов ограничение в три раза превышает значение flow гарантии. Например, при гарантии resource_flow/cpu равной 1000, планировщик по умолчанию ограничит потребление пула тремя тысячами ядер в моменте.

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

Пример

Пусть есть продакшен процесс, требующий 2000 CPU 12 часов в сутки, и исследовательский (research) процесс, которому достаточно 1000 CPU в среднем. С помощью механизма интегральных гарантий можно сконфигурировать для таких процессов burst и relaxed пулы, и для обеспечения гарантий потребуется 2000 ядер. Указанные пулы должны находиться в одном дереве пулов, других ограничений нет. При использовании базового механизма выдачи гарантий (строгая гарантии) для строго соблюдения таких гарантий пришлось бы заказать 3000 ядер.

На рисунке приведён график потребления (usage) и потребности (demand) в CPU для burst пула, для которого burst_integral гарантия равна 500 CPU, а resource_flow равен 100 CPU.

На рисунке ниже приведён график объёма накопленного ресурса для того же пула. Видно, как объём виртуального ресурса уменьшается при запущенных операциях в пуле, а после ресурс вновь накапливается до заданного предела.

Сочетание со строгими гарантиями

Оба вида интегральных пулов естественным образом совместимы со строгими гарантиями. При выдаче ресурсов планировщик сперва будет выдавать ресурсы в счёт строгих гарантий. Если их достаточно для покрытия текущей потребности пула, то accumulated_resource_ratio_volume расходоваться не будет. Если потребность в ресурсах превышает строгие гарантии, то для удовлетворения превышающей части будет потрачен accumulated_resource_ratio_volume.

Интегральные пулы наравне с соседними пулами участвуют в получении ресурсов сверх своих гарантий от пулов выше по иерархии пропорционально выставленным весам.

Дополнительные атрибуты интегральных пулов

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

  • accumulated_resource_ratio_volume — накопленные интегральные ресурсы в терминах доли кластера * секунду;
  • accumulated_resource_volumeaccumulated_resource_ratio_volume в виде словаря со всеми ресурсами. Например, accumulated_resource_volume/cpu — это объём накопленного интегрального ресурса, выраженного в ядро * секунду;
  • integral_pool_capacity — предел накопления accumulated_resource_ratio_volume;
  • specified_burst_ratioburst_guarantee_resources, переведённые в долю кластера;
  • specified_resource_flow_ratioresource_flow, переведённый в долю кластера;
  • total_burst_ratio — сумма specified_burst_ratio по всем потомкам (включая текущий пул);
  • total_resource_flow_ratio — сумма specified_resource_flow_ratio по всем потомкам (включая текущий пул);
  • estimated_burst_usage_duration_seconds — предполагаемый промежуток времени, на который хватит накопленного ресурса (с учётом продолжающегося поступления ресурсов со скоростью resource_flow), при потреблении burst_guarantee_resources (есть только у burst пулов).

Пример запроса атрибута представлен в листинге 4.
Листинг 4

yt get //sys/scheduler/orchid/scheduler/scheduling_info_per_pool_tree/physical/fair_share_info/pools/pool_name/integral_pool_capacity

Внимание

Орхидея планировщика не является частью стабильного API и может изменяться без анонсов.