Compartilhar via


Perfil de uso de memória de aplicativos Python no Azure Functions

Durante o desenvolvimento ou depois de implantar seu projeto de aplicativo de funções Python local no Azure, é uma boa prática analisar possíveis gargalos de memória em suas funções. Esses afunilamentos podem diminuir o desempenho de suas funções e gerar erros. As instruções a seguir mostram como usar o pacote Python de memory-profiler, que fornece a análise de consumo de memória linha por linha de suas funções à medida que elas são executadas.

Observação

A criação de perfil de memória destina-se apenas à análise de superfície de memória em ambientes de desenvolvimento. Não aplique o criador de perfil de memória em aplicativos de função de produção.

Pré-requisitos

Antes de começar a desenvolver um aplicativo de funções do Python, você deve atender a estes requisitos:

Caso você não tenha uma assinatura do Azure, crie uma conta gratuita do Azure antes de começar.

Processo de criação de perfil de memória

  1. Em seu requirements.txt, adicione memory-profiler para garantir que o pacote é agrupado com sua implantação. Se você estiver desenvolvendo em seu computador local, talvez queira ativar um ambiente virtual Python e fazer uma resolução de pacote pip install -r requirements.txt.

  2. No script de função (por exemplo, __init__.py para o modelo de programação Python v1 e function_app.py para o modelo v2), adicione as linhas a seguir acima da função main(). Essas linhas garantem que o agente raiz relate os nomes dos agentes filho, para que os logs de criação de perfil de memória sejam distinguíveis pelo prefixo 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. Aplique o decorador a seguir acima de qualquer função que precise de criação de perfil de memória. O decorador não funciona diretamente no método main() de ponto de entrada de gatilho. Você precisa criar subfunções e decorá-las. Além disso, devido a um problema conhecido do criador de perfil de memória, ao aplicar a uma corrotina assíncrona, o valor retornado da corrotina sempre é None.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Teste o criador de perfil de memória no computador local usando o comando func host start do Azure Functions Core Tools. Quando você invoca as funções, elas devem gerar um relatório de uso de memória. O relatório contém o nome do arquivo, a linha de código, o uso de memória, o incremento de memória e o conteúdo da linha.

  5. Para verificar os logs de criação de perfil de memória em uma instância de aplicativo de funções existente no Azure, você pode consultar os logs de criação de perfil de memória em invocações recentes com consultas Kusto no Application Insights, Logs.

    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
    

Exemplo

Aqui está um exemplo de como executar a criação de perfil de memória em gatilhos HTTP assíncronos e síncronos, chamados "HttpTriggerAsync" e "HttpTriggerSync", respectivamente. Criaremos um aplicativo de funções do Python que simplesmente envia solicitações GET para a página inicial da Microsoft.

Criar um aplicativo de funções do Python

Um aplicativo de funções do Python deve seguir a estrutura de pastas especificada do Azure Functions. Para realizar o scaffold do projeto, é recomendável usar o Azure Functions Core Tools executando os seguintes comandos:

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

Atualizar o conteúdo do arquivo

O requirements.txt define os pacotes que são usados em nosso projeto. Além do Azure Functions SDK e do memory-profiler, introduzimos aiohttp para solicitações HTTP assíncronas e requests para chamadas HTTP síncronas.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Crie o gatilho HTTP assíncrono.

Substitua o código no gatilho HTTP assíncrono HttpTriggerAsync/__init__.py pelo código a seguir, que configura o criador de perfil de memória, o formato do agente raiz e a associação de streaming do agente.

# 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

Crie o gatilho HTTP síncrono.

Substitua o código no gatilho HTTP assíncrono HttpTriggerSync/__init__.py pelo código a seguir.

# 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

Aplicativo de funções Python de perfil no ambiente de desenvolvimento local

Depois de fazer todas as alterações acima, há mais algumas etapas para inicializar um ambiente virtual do Python para o runtime do Azure Functions.

  1. Abra um Windows PowerShell ou qualquer shell do Linux como preferir.

  2. Crie um ambiente virtual do Python por py -m venv .venv no Windows ou python3 -m venv .venv no Linux.

  3. Ative o ambiente virtual do Python com .venv\Scripts\Activate.ps1 no Windows PowerShell ou source .venv/bin/activate no shell do Linux.

  4. Restaurar as dependências do Python com pip install -r requirements.txt

  5. Inicie o runtime do Azure Functions localmente com Azure Functions Core Tools func host start

  6. Envie uma solicitação GET para https://localhost:7071/api/HttpTriggerAsync ou https://localhost:7071/api/HttpTriggerSync.

  7. Ela deve mostrar um relatório de criação de perfil de memória semelhante à seção a seguir no Azure Functions 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()
    

Próximas etapas

Para obter mais informações sobre o desenvolvimento do Python do Azure Functions consulte os seguintes recursos: