Наилучший способ ограничить максимальное количество выполняемых активных функций Azure за интервал времени

#azure #azure-functions #azure-durable-functions

#azure #azure-функции #azure-durable-функции

Вопрос:

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

Способ настройки моего потока, как показано ниже:

  • Функция HistorySynchronizer_HttpStart: имеет HttpTrigger и DurableClient привязки в подписи и вызывает следующую функцию оркестровки:
  • Функция HistorySynchronizer: имеет OrchestrationTrigger привязку в подписи. Эта функция вызовет API (await) и вернет коллекцию. Для каждого элемента в этой коллекции он запустит новое действие: context.CallActivityAsync() (объединение их в a List и выполнение a Task.WhenAll() )
  • Функции ProcessActivity: имеет ActivityTrigger привязку в подписи. Эта функция должна будет выполнить вызов конечной точки API с ограниченной скоростью. И именно эти действия я хочу ограничить (в нескольких оркестровках).

Итак, то, что я ищу, — это реализация шаблона регулирования:

  • Мне нужно потокобезопасное общее состояние (я думал о долговременной сущности), которое отслеживает количество вызовов, выполненных с этим API
  • Прежде чем функция ProcessActivity выполнит вызов этого API, она должна проверить у объекта Durable, может ли он вызвать API, или ему нужно подождать определенный промежуток времени перед выполнением этого вызова.
  • В случае, если придется ждать, действие должно будет «спать», и я думал о долговременном таймере, но, похоже, его следует использовать в функции оркестровки, а не в функции Activity.
  • В случае, если вызов API разрешен, действие должно обновить счетчик скорости в этом объекте общего состояния.

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

Будет ли лучшим подходом реализовать подрегулировку для каждого вызова API, который должен регулироваться, где должна выполняться проверка, перед вызовом Activity?

С нетерпением жду любой информации.

Комментарии:

1. пожалуйста, посмотрите мой ответ здесь youtube.com/watch?v=sH4t3cs9qkM

Ответ №1:

Сэм, я вижу несколько вариантов. Я также создал видео в ответ на это. Давайте сделаем шаг назад и посмотрим, как мы могли бы это сделать, используя обычные функции (не durable).

Первый подход заключается в том, чтобы превратить функцию в функцию, запускаемую очередью, и использовать механизм очереди для управления масштабированием, используя batchSize и newBatchThreshold :

введите описание изображения здесь

Другим способом было бы иметь функцию, запускаемую http, и использовать ее в host.js файл:

введите описание изображения здесь

С помощью durable functions мы можем это сделать:

введите описание изображения здесь

Вы специально спрашивали об управлении масштабированием за интервал времени, и вот как я бы это сделал:

  1. преобразуйте вашу функцию activity для запуска в очереди
  2. при каждом выполнении функции, запускаемой очередью, эта функция вставляет запись в хранилище таблиц, указывающую на активный запуск
  3. перед фактическим запуском внешнего http-вызова проверьте хранилище таблиц, чтобы узнать, сколько существует активных подключений.
  4. если количество текущих подключений меньше X, Обработайте сообщение (т. Е. Выполните внешний вызов), если хранилище таблиц показывает, что все подключения приняты, затем поместите сообщение обратно в очередь!

Комментарии:

1. Спасибо, Алекс, что уделил так много времени ответу на вышеуказанное. Моя цель состояла в том, чтобы как можно больше полагаться на надежные функции, поскольку у них, похоже, есть длительные спящие (таймеры), долговечные объекты (так зачем мне беспокоиться о табличном хранилище, если фреймворк что-то предоставляет). Я надеялся сделать это, не полагаясь на очереди служебной шины. Приведенный выше вариант будет скорее резервным вариантом на случай, если Durable Functions не предложит что-то из коробки

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

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

Ответ №2:

Есть лучший способ сделать это. Вместо того, чтобы пытаться ограничить его на своей стороне на основе функций параллельной активности или активных HTTP-запросов, почему бы вам не полагаться на сам API? Он знает, когда пришло время вернуть 429.

Я бы добавил очередь, захватил задачу, вызвал API, если есть 429, вернул сообщение о задаче в очередь с экспоненциальной политикой задержки.

Ответ №3:

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

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

Каждый из них в основном делает то же самое:

  • Получить ресурс API из функции activity
  • Просмотрите элементы ответа и вызовите одну или несколько функций подорганизаторов. (До нижней части дерева)
  • Верните ответ родительскому оркестратору.

Идея состоит в том, чтобы скопировать весь Rest API в Azure data lake как часть процесса ETL. (Уровень извлечения)

Например: Клиенты => Заказы => Счета-фактуры

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

Я думаю о другом решении, которое будет работать с синхронизированным деревом оркестровки.

  1. Создайте функцию оркестровки обертывания вокруг функции activity, которую мы хотим ограничить. (мы не можем ждать от activity) Эта функция выполнит следующее:

    • добавьте собственный идентификатор экземпляра в некоторую очередь хранилища
    • дождитесь внешнего события — «HttpRequestAllowed»
    • продолжайте в обычном режиме. (вызовите действие, выполните следующие задачи)
  2. Создайте отдельную клиентскую функцию, которая выполняет следующее:

    • считайте один идентификатор экземпляра из очереди
    • вызовите событие «HttpRequestAllowed» для этого идентификатора экземпляра
    • подождите некоторое время (по ограничению скорости) и обработайте следующий идентификатор экземпляра
    • продолжайте до конца выполнения

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