Поделиться через


Профилирование использования памяти приложениями Python в службе "Функции Azure"

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

Примечание.

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

Необходимые компоненты

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

Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.

Процесс профилирования памяти

  1. В файле requirements.txt добавьте memory-profiler , чтобы убедиться, что пакет упаковается в развертывание. Если вы разрабатываете на локальном компьютере, вы можете активировать виртуальную среду Python и выполнить разрешение пакета.pip install -r requirements.txt

  2. В скрипте функции (например, __init__.py для модели программирования Python версии 1 и function_app.py для модели версии 2) добавьте следующие строки над main() функцией. Эти строки гарантируют, что корневой средство ведения журнала сообщает имена дочерних средств ведения журнала, чтобы журналы профилирования памяти отличались префиксом memory_profiler_logs.

    import logging
    import memory_profiler
    root_logger = logging.getLogger()
    root_logger.handlers[0].setFormatter(logging.Formatter("%(name)s: %(message)s"))
    profiler_logstream = memory_profiler.LogFile('memory_profiler_logs', True)
    
  3. Примените следующий декоратор над любыми функциями, которым требуется профилирование памяти. Декоратор не работает непосредственно с методом точки main() входа триггера. Необходимо создать подфункции и дополнить их. Кроме того, из-за известной проблемы с профилировщиком памяти при применении к асинхронной корутине возвращаемое значение всегда None.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Проверьте профилировщик памяти на локальном компьютере с помощью команды func host startФункции Azure Core Tools. При вызове функций они должны создать отчет об использовании памяти. Отчет содержит имя файла, строку кода, использование памяти, увеличение памяти и содержимое строки.

  5. Чтобы проверка журналы профилирования памяти в существующем экземпляре приложения-функции в Azure, можно запросить журналы профилирования памяти для последних вызовов с помощью запросов Kusto в приложении Аналитика журналов.

    Screenshot showing the query memory usage of a Python app in Application Insights.

    traces
    | where timestamp > ago(1d)
    | where message startswith_cs "memory_profiler_logs:"
    | parse message with "memory_profiler_logs: " LineNumber "  " TotalMem_MiB "  " IncreMem_MiB "  " Occurrences "  " Contents
    | union (
        traces
        | where timestamp > ago(1d)
        | where message startswith_cs "memory_profiler_logs: Filename: "
        | parse message with "memory_profiler_logs: Filename: " FileName
        | project timestamp, FileName, itemId
    )
    | project timestamp, LineNumber=iff(FileName != "", FileName, LineNumber), TotalMem_MiB, IncreMem_MiB, Occurrences, Contents, RequestId=itemId
    | order by timestamp asc
    

Пример

Ниже приведен пример выполнения профилирования памяти на асинхронном и синхронном триггере HTTP с именем HttpTriggerAsync и HttpTriggerSync соответственно. Мы создадим приложение-функцию Python, которое просто отправляет запросы GET на домашнюю страницу Майкрософт.

Создание приложения-функции Python

Приложение-функция Python должно соответствовать заданной в службе "Функции Azure" структуре папок. Чтобы сформировать шаблон проекта, рекомендуется использовать Azure Functions Core Tools, выполнив следующие команды:

func init PythonMemoryProfilingDemo --python
cd PythonMemoryProfilingDemo
func new -l python -t HttpTrigger -n HttpTriggerAsync -a anonymous
func new -l python -t HttpTrigger -n HttpTriggerSync -a anonymous

Обновление содержимого файла

В файле requirements.txt определяются пакеты, используемые в нашем проекте. Помимо пакета SDK для службы "Функции Azure" и профилировщика памяти, мы представляем aiohttp для асинхронных HTTP-запросов и requests для синхронных HTTP-вызовов.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Создайте асинхронный триггер HTTP.

Замените код в асинхронном триггере HTTPTriggerAsync/__init__.py следующим кодом, который настраивает профилировщик памяти, формат корневого средства ведения журнала и привязку потоковой передачи средства ведения журнала.

# HttpTriggerAsync/__init__.py

import azure.functions as func
import aiohttp
import logging
import memory_profiler

# Update root logger's format to include the logger name. Ensure logs generated
# from memory profiler can be filtered by "memory_profiler_logs" prefix.
root_logger = logging.getLogger()
root_logger.handlers[0].setFormatter(logging.Formatter("%(name)s: %(message)s"))
profiler_logstream = memory_profiler.LogFile('memory_profiler_logs', True)

async def main(req: func.HttpRequest) -> func.HttpResponse:
    await get_microsoft_page_async('https://microsoft.com')
    return func.HttpResponse(
        f"Microsoft page loaded.",
        status_code=200
    )

@memory_profiler.profile(stream=profiler_logstream)
async def get_microsoft_page_async(url: str):
    async with aiohttp.ClientSession() as client:
        async with client.get(url) as response:
            await response.text()
    # @memory_profiler.profile does not support return for coroutines.
    # All returns become None in the parent functions.
    # GitHub Issue: https://github.com/pythonprofilers/memory_profiler/issues/289

Создайте синхронный триггер HTTP.

Замените код в асинхронном триггере HTTPTriggerSync/__init__.py следующим кодом.

# HttpTriggerSync/__init__.py

import azure.functions as func
import requests
import logging
import memory_profiler

# Update root logger's format to include the logger name. Ensure logs generated
# from memory profiler can be filtered by "memory_profiler_logs" prefix.
root_logger = logging.getLogger()
root_logger.handlers[0].setFormatter(logging.Formatter("%(name)s: %(message)s"))
profiler_logstream = memory_profiler.LogFile('memory_profiler_logs', True)

def main(req: func.HttpRequest) -> func.HttpResponse:
    content = profile_get_request('https://microsoft.com')
    return func.HttpResponse(
        f"Microsoft page response size: {len(content)}",
        status_code=200
    )

@memory_profiler.profile(stream=profiler_logstream)
def profile_get_request(url: str):
    response = requests.get(url)
    return response.content

Профилирование приложения-функции Python в локальной среде разработки

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

  1. Откройте Windows PowerShell или любую оболочку Linux по своему выбору.

  2. Создайте виртуальную среду Python с помощью py -m venv .venv в ОС Windows или python3 -m venv .venv в Linux.

  3. Активируйте виртуальную среду Python с .venv\Scripts\Activate.ps1 помощью Windows PowerShell или source .venv/bin/activate оболочки Linux.

  4. Восстановите зависимости Python с помощью pip install -r requirements.txt

  5. Запустите среду выполнения службы "Функции Azure" на локальном компьютере с помощью func host start Azure Functions Core Tools.

  6. Отправьте запрос GET в https://localhost:7071/api/HttpTriggerAsync или https://localhost:7071/api/HttpTriggerSync.

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

    Filename: <ProjectRoot>\HttpTriggerAsync\__init__.py
    Line #    Mem usage    Increment  Occurrences   Line Contents
    ============================================================
        19     45.1 MiB     45.1 MiB           1   @memory_profiler.profile
        20                                         async def get_microsoft_page_async(url: str):
        21     45.1 MiB      0.0 MiB           1       async with aiohttp.ClientSession() as client:
        22     46.6 MiB      1.5 MiB          10           async with client.get(url) as response:
        23     47.6 MiB      1.0 MiB           4               await response.text()
    

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

Дополнительные сведения о разработках под Python в рамках службы "Функции Azure" см. в статьях ниже.