Производительность и масштабирование в устойчивых функциях (Функции Azure)

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

Масштабирование рабочих ролей

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

Эта концепция представлена на схеме ниже:

Worker scaling diagram

Автоматическое масштабирование

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

Примечание.

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

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

Использование процессора

Функции оркестратора выполняются в одном потоке, чтобы выполнение было можно разделить на множество воспроизведений. Так как выполнение является однопоточным, очень важно, чтобы потоки функции оркестратора по любой причине не выполняли задачи, интенсивно использующие ЦП, операции ввода-вывода или блокировку. Все операции, которым может потребоваться ввод-вывод, блокировка или несколько потоков, должны выполняться с помощью функций действий.

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

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

Время ожидания функций

Для функций действия, оркестратора и сущности действуют те же тайм-ауты функций, что и для всех функций Azure. Как правило, Устойчивые функции обрабатывают тайм-ауты функций так же, как и необработанные исключения, создаваемые кодом приложения.

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

Пакетная обработка операций сущностей

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

По умолчанию максимальный размер пакета составляет 50 для планов потребления и 5000 для всех остальных планов. Максимальный размер пакета также можно настроить в файле host.json. Если максимальный размер пакета равен 1, пакетная обработка фактически отключена.

Примечание.

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

Кэширование экземпляров

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

  1. Получение журнала оркестрации.
  2. Воспроизведение кода оркестратора с помощью журнала.

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

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

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

Поставщик хранилищ Azure Поставщик хранилищ Netherite Поставщик хранилища MSSQL
Кэширование экземпляров Поддерживается
(Только для внутрипроцессных рабочих ролей .NET)
Поддерживается Не поддерживается
Значение по умолчанию Выключено Включен Н/Д
Механизм Расширенные сеансы Кэш экземпляров Н/Д
Документация См. раздел Расширенные сеансы См. раздел Кэш экземпляров Н/Д

Совет

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

Сравнение механизмов кэширования

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

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

Примечание.

Расширенные сеансы поддерживаются только во внутрипроцессных рабочих ролях .NET.

  • Кэш экземпляра, используемый поставщиком хранилища Netherite, сохраняет состояние всех экземпляров, включая их журналы, в памяти рабочей роли, отслеживая общий объем используемой памяти. Если размер кэша превышает ограничение, настроенное InstanceCacheSizeMB, последние использованные данные экземпляра вытесняются. Если для параметра CacheOrchestrationCursors задано значение true, кэш также сохраняет оркестраторы среднего выполнения вместе с состоянием экземпляра. Дополнительные сведения см. в разделе Кэш экземпляров документации по поставщику хранилища Netherite.

Примечание.

Кэши экземпляров работают для всех языковых пакетов SDK, но параметр CacheOrchestrationCursors доступен только для внутрипроцессной рабочей роли .NET.

Регулирование параллелизма

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

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

Примечание.

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

Совет

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

Настройка регулирования

Ограничения параллелизма для функции действия, оркестратора и сущности можно настроить в файле host.json. Соответствующие параметры — durableTask/maxConcurrentActivityFunctions для функций действия и durableTask/maxConcurrentOrchestratorFunctions для функций оркестратора и сущности. Эти параметры управляют максимальным числом функций оркестратора, сущности или действия, которые могут быть загружены в память одной рабочей роли.

Примечание.

Оркестрации и сущности загружаются в память только тогда, когда они активно обрабатывают события или операции или когда включено кэширование экземпляров. После выполнения логики и ожидания (т. е. при достижении метода await (C#) или yield (JavaScript, Python) в коде функции оркестратора) они могут быть выгружены из памяти. Оркестрации и сущности, выгруженные из памяти, не учитываются при регулировании maxConcurrentOrchestratorFunctions. Даже если миллионы оркестраций или сущностей находятся в состоянии "Выполнение", они учитываются в ограничении регулирования только тогда, когда загружены в активную память. Оркестрация, планирующая функцию действия, также не учитывается в регулировании, если она ожидает завершения выполнения действия.

Функции 2.0

{
  "extensions": {
    "durableTask": {
      "maxConcurrentActivityFunctions": 10,
      "maxConcurrentOrchestratorFunctions": 10
    }
  }
}

Функции 1.x

{
  "durableTask": {
    "maxConcurrentActivityFunctions": 10,
    "maxConcurrentOrchestratorFunctions": 10
  }
}

Рекомендации по языковой среде выполнения

Выбранная языковая среда выполнения может устанавливать строгие ограничения параллелизма или функций. Например, приложения с устойчивыми функциями, написанные на Python или PowerShell, могут поддерживать выполнение за один раз только одной функции на одной виртуальной машине. Это может привести к значительным проблемам с производительностью. Например, если оркестратор должен развертывать до 10 действий, но языковая среда выполнения ограничивает параллелизм только одной функцией, то 9 из 10 функций действия зависнут в ожидании выполнения. Более того, эти 9 зависших действий нельзя сбалансировать для других рабочих ролей, поскольку среда выполнения устойчивых функций уже загрузила их в память. Это особенно проблематично, если функции действий выполняются долго.

Если используемая языковая среда выполнения накладывает ограничение на параллелизм, следует обновить параметры параллелизма устойчивых функций в соответствии с параметрами параллелизма языковой среды выполнения. Это гарантирует, что среда выполнения устойчивых функций не будет пытаться одновременно выполнять больше функций, чем разрешено в языковой среде выполнения, что позволит произвести балансировку нагрузки всех ожидающих действий на других виртуальных машинах. Например, если в приложении Python существует ограничение параллелизма до 4 функций (возможно, оно настроено на 4 потока в рабочем процессе с одним языком или на 1 поток в рабочих процессах с 4 языками), следует указать значение 4 для обоих параметров maxConcurrentOrchestratorFunctions и maxConcurrentActivityFunctions.

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

Количество секций

Некоторые поставщики хранилища используют механизм секционирования и позволяют указать параметр partitionCount.

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

Примечание.

Секционирование ограничивает горизонтальное увеличение масштаба, так как обрабатывать рабочие элементы из секционируемой очереди могут не более partitionCount рабочих ролей.

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

Поставщик хранилищ Azure Поставщик хранилищ Netherite Поставщик хранилища MSSQL
Сообщения экземпляров Partitioned Partitioned Не секционируются
Сообщения о действиях Не секционируются Partitioned Не секционируются
Значение partitionCount по умолчанию 4 12 Н/Д
Максимальное значение partitionCount 16 32 Н/Д
Документация См. раздел Развертывание оркестратора См. раздел Рекомендации по выбору числа секций Н/Д

Предупреждение

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

Настройка количества секций

Параметр partitionCount может быть указан в файле host.json. В следующем примере фрагмента кода host.json свойство durableTask/storageProvider/partitionCount (или durableTask/partitionCount для устойчивых функции 1.x) устанавливается в значение 3.

Устойчивые функции 2.x

{
  "extensions": {
    "durableTask": {
      "storageProvider": {
        "partitionCount": 3
      }
    }
  }
}

Устойчивые функции 1.x

{
  "extensions": {
    "durableTask": {
      "partitionCount": 3
    }
  }
}

Рекомендации по минимизации задержки вызовов

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

Цели анализа производительности

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

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

Пропускная способность для этих сценариев приведена в соответствующей документации для поставщиков хранилища. В частности:

Совет

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

Следующие шаги