Profilování využití paměti aplikací v Pythonu ve službě Azure Functions

Během vývoje nebo po nasazení místního projektu aplikace funkcí Pythonu do Azure je vhodné analyzovat potenciální kritické body paměti ve vašich funkcích. Takové kritické body můžou snížit výkon vašich funkcí a vést k chybám. Následující pokyny ukazují, jak používat balíček Pythonu profiler paměti, který poskytuje analýzu spotřeby paměti jednotlivých řádků vašich funkcí při jejich provádění.

Poznámka:

Profilace paměti je určená pouze pro analýzu stop paměti ve vývojových prostředích. Nepoužívejte profiler paměti v produkčních aplikacích funkcí.

Předpoklady

Než začnete vyvíjet aplikaci funkcí Pythonu, musíte splnit tyto požadavky:

Pokud ještě nemáte předplatné Azure, vytvořte si bezplatný účet Azure před tím, než začnete.

Proces profilace paměti

  1. Do souboru requirements.txt přidejte memory-profiler , abyste zajistili, že je balíček součástí vašeho nasazení. Pokud vyvíjíte na místním počítači, možná budete chtít aktivovat virtuální prostředí Pythonu a provést překlad balíčku .pip install -r requirements.txt

  2. Do skriptu funkce (například __init__.py pro programovací model Pythonu v1 a function_app.py pro model v2) přidejte nad funkci následující řádky main() . Tyto řádky zajišťují, že kořenový protokolovacíovač hlásí podřízené názvy protokolovacího nástroje, aby protokoly profilace paměti byly rozlišitelné předponou 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. Použijte následující dekorátor nad všemi funkcemi, které potřebují profilaci paměti. Dekorátor nefunguje přímo na metodě triggeru entrypointu main() . Potřebujete vytvořit dílčí funkce a ozdobit je. Také kvůli známému problému s profilerem paměti při použití asynchronní korutiny je návratová hodnota korutin vždy None.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Otestujte profiler paměti na místním počítači pomocí příkazu func host startAzure Functions Core Tools . Při vyvolání funkcí by měly vygenerovat sestavu využití paměti. Sestava obsahuje název souboru, řádek kódu, využití paměti, přírůstek paměti a obsah řádku.

  5. Pokud chcete zkontrolovat protokoly profilace paměti v existující instanci aplikace funkcí v Azure, můžete dotazovat protokoly profilace paměti na nedávné vyvolání pomocí dotazů Kusto v aplikaci Přehledy protokoly.

    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
    

Příklad

Tady je příklad profilace paměti u asynchronního a synchronního triggeru HTTP s názvem HttpTriggerAsync a HttpTriggerSync. Vytvoříme aplikaci funkcí Pythonu, která jednoduše odešle požadavky GET na domovskou stránku Microsoftu.

Vytvoření aplikace funkcí Pythonu

Aplikace funkcí v Pythonu by měla dodržovat zadanou strukturu složek Azure Functions. Pokud chcete projekt vygenerovat, doporučujeme použít nástroje Azure Functions Core Tools spuštěním následujících příkazů:

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

Aktualizace obsahu souboru

Soubor requirements.txt definuje balíčky, které se používají v našem projektu. Kromě sady Azure Functions SDK a profileru paměti zavádíme aiohttp asynchronní požadavky HTTP a requests synchronní volání HTTP.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Vytvořte asynchronní trigger HTTP.

Nahraďte kód v asynchronním triggeru HTTP HttpTriggerAsync/__init__.py následujícím kódem, který konfiguruje profiler paměti, formát kořenového protokolovacího modulu a vazbu streamování protokolovacího modulu.

# 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

Vytvořte synchronní trigger HTTP.

Nahraďte kód v asynchronním triggeru HTTP HttpTriggerSync/__init__.py následujícím kódem.

# 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

Profilování aplikace funkcí Pythonu v místním vývojovém prostředí

Po provedení výše uvedených změn je několik dalších kroků pro inicializaci virtuálního prostředí Pythonu pro modul runtime Azure Functions.

  1. Otevřete prostředí Windows PowerShell nebo libovolné linuxové prostředí podle potřeby.

  2. Vytvořte virtuální prostředí Pythonu ve py -m venv .venv Windows nebo python3 -m venv .venv v Linuxu.

  3. Aktivujte virtuální prostředí Pythonu v .venv\Scripts\Activate.ps1 prostředí Windows PowerShell nebo source .venv/bin/activate v linuxovém prostředí.

  4. Obnovení závislostí Pythonu pomocí pip install -r requirements.txt

  5. Místní spuštění modulu runtime Azure Functions pomocí nástrojů Azure Functions Core Tools func host start

  6. Odeslat požadavek GET do https://localhost:7071/api/HttpTriggerAsync nebo https://localhost:7071/api/HttpTriggerSync.

  7. V nástrojích Azure Functions Core Tools by se měla zobrazit sestava profilace paměti podobná následující části.

    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()
    

Další kroky

Další informace o vývoji v Pythonu pro Azure Functions najdete v následujících zdrojích informací: