Как языковые работники работают в Azure функциях, используя Python? - PullRequest
1 голос
/ 09 мая 2020

Я работаю над проектом ETL с использованием Azure функций, в которых я извлекаю данные из хранилища BLOB-объектов, преобразую данные в Python и pandas и загружаю данные с помощью pandas to_ sql () . Я пытаюсь сделать этот процесс более эффективным, используя asyncio и языковые работники.

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

Означает ли это, что если я не использую asyn c ключевое слово, мои методы будут выполняться одновременно с использованием языковых рабочих? Должен ли я использовать asyncio для использования языковых рабочих?

Кроме того, в документации указано, что Azure Функции могут масштабироваться до 200 экземпляров. Как я могу масштабироваться до такого количества экземпляров, если мне разрешено не более 10 языковых работников?

Edit: Спасибо, Анатолий. Просто чтобы уточнить, если у меня есть триггер таймера со следующим кодом:

import azure.functions as func
from . import client_one_etl
from . import client_two_etl

def main(mytimer: func.TimerRequest) -> None:
    client_one_etl.main()
    client_two_etl.main()

Если я увеличил количество языковых рабочих, означает ли это, что оба client_one_etl.main() и client_two_etl.main() автоматически запускаются отдельно темы даже без использования asyncio? И если client_two_etl.main() требует client_one_etl.main() для завершения sh перед выполнением, мне нужно будет использовать async await, чтобы они не работали одновременно?

А для отдельных экземпляров, если client_one_etl.main() и client_two_etl.main() не полагаются друг на друга. Означает ли это, что я могу выполнять их в одном приложении Azure Function как отдельные сценарии .py, которые выполняются на их собственной виртуальной машине? Можно ли запускать несколько триггеров таймера (вызывая несколько сценариев __init__.py каждый в своей виртуальной машине для одной функции Azure)? Тогда все скрипты нужно будет завершить в течение 10 минут, если я увеличу functionTimeout в файле host.json?

1 Ответ

2 голосов
/ 09 мая 2020

FUNCTIONS_WORKER_PROCESS_COUNT ограничивает максимальное количество рабочих процессов на один экземпляр узла функций. Если вы установите его на 10, каждый экземпляр хоста сможет одновременно выполнять до 10 Python функций. Каждый рабочий процесс по-прежнему будет выполнять код Python в одном потоке, но теперь у вас есть до 10 из них, работающих одновременно. Для этого не нужно использовать asyncio. (Сказав это, есть законные причины для использования asyncio для улучшения масштабируемости и использования ресурсов, но у вас нет для этого, чтобы воспользоваться преимуществами нескольких Python рабочих процессов.)

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

UPDATE (отвечая на дополнительные вопросы):

Как только поскольку вызов вашей функции запускается на определенном воркере, он будет работать на этом воркере до завершения. В рамках этого вызова выполнение кода будет не распространяться на другие рабочие процессы или экземпляры узлов функций, и оно не будет автоматически распараллеливаться для вас каким-либо другим способом. В вашем примере client_two_etl.main() начнется после выхода client_one_etl.main(), и он будет запускаться в том же рабочем процессе, поэтому вы не увидите никакого параллелизма, независимо от настроенных ограничений (если вы не сделаете что-то особенное в client_*_etl.main()).

Когда несколько вызовов происходят примерно в одно и то же время, эти вызовы могут быть автоматически распределены между несколькими воркерами, и именно здесь применяются упомянутые выше ограничения. Каждый вызов по-прежнему будет выполняться ровно на одном воркере от начала до конца sh. В вашем примере, если вам удастся вызвать эту функцию дважды примерно в одно и то же время, каждый вызов может получить своего собственного рабочего, и они могут выполняться одновременно, но каждый будет выполнять как client_one_etl.main(), так и client_two_etl.main() последовательно.

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

Если вы действительно хотите запускать независимые client_one_etl.main() и client_two_etl.main() одновременно, наиболее естественным будет их вызов из разных функций, каждая из которых реализована в отдельном __init__.py с собственным триггером, в одном или разных приложениях-функциях.

functionTimeout в host.json применяется для вызова функции . Итак, если в вашем приложении несколько функций, каждый вызов должен выполняться в пределах указанного лимита. Это не означает, что все вместе должны быть выполнены в пределах этого лимита (если я правильно понял ваш вопрос).

ОБНОВЛЕНИЕ 2 (ответ на дополнительные вопросы):

@ JohnT Обратите внимание, что я не говорю о количестве приложений или ___init___.py скриптов . Функция (описываемая ___init___.py) - это программа , которая определяет, что необходимо сделать. Вы можете создать более 10 функций для каждого приложения, но не делайте этого для увеличения параллелизма - это не поможет. Вместо этого добавьте функции для разделения логически независимых и согласованных программ. Функция invocation - это процесс, который активно выполняет программу, и именно здесь применяются ограничения, о которых я говорю. Вы должны четко понимать разницу между функцией и вызовом функции .

Теперь, чтобы вызвать функцию, вам нужен рабочий процесс, выделенный для этого вызова, пока этот вызов не будет завершен. Затем, чтобы запустить рабочий процесс, вам понадобится машина, на которой будет размещен этот процесс. Это то, что является экземпляром хоста функций (не очень точное определение экземпляра хоста функций, но достаточно хорошее для целей этого обсуждения). При работе по плану потребления ваше приложение может масштабироваться до 200 хост-экземпляров функций, и каждый из них по умолчанию запускает один рабочий процесс (потому что FUNCTIONS_WORKER_PROCESS_COUNT = 1), поэтому вы можете запускать до 200 вызовов функций одновременно. Увеличение значения FUNCTIONS_WORKER_PROCESS_COUNT позволит каждому экземпляру узла функций создавать более одного рабочего процесса, поэтому каждый экземпляр узла функций может обрабатывать до вызовов функций FUNCTIONS_WORKER_PROCESS_COUNT, в результате чего потенциальное общее количество достигает 2000.

Обратите внимание, что " can scale out »не обязательно означает« будет масштабироваться ». Для получения дополнительных сведений см. Azure Масштабирование функций и хостинг и Azure Ограничения функций .

...