Profilera minnesanvändning för Python-appar i Azure Functions

Under utvecklingen eller efter distributionen av ditt lokala Python-funktionsappsprojekt till Azure är det en bra idé att analysera potentiella minnesflaskhalsar i dina funktioner. Sådana flaskhalsar kan minska prestandan för dina funktioner och leda till fel. Följande instruktioner visar hur du använder Python-paketet memory-profiler , som tillhandahåller analys av minnesförbrukning rad för rad av dina funktioner när de körs.

Kommentar

Minnesprofilering är endast avsedd för analys av minnesfotavtryck i utvecklingsmiljöer. Använd inte minnesprofilering på produktionsfunktionsappar.

Förutsättningar

Innan du börjar utveckla en Python-funktionsapp måste du uppfylla följande krav:

Om du inte har en Azure-prenumeration skapar du ett kostnadsfritt Azure-konto innan du börjar.

Minnesprofileringsprocess

  1. I din requirements.txt lägger du till memory-profiler för att säkerställa att paketet paketeras med din distribution. Om du utvecklar på den lokala datorn kanske du vill aktivera en virtuell Python-miljö och utföra en paketmatchning med pip install -r requirements.txt.

  2. Lägg till följande rader ovanför main() funktionen i funktionsskriptet (till exempel __init__.py för python v1-programmeringsmodellen och function_app.py för v2-modellen). Dessa rader ser till att rotloggaren rapporterar de underordnade loggningsnamnen, så att minnesprofileringsloggarna kan särskiljas med prefixet 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. Använd följande dekoratör ovanför alla funktioner som behöver minnesprofilering. Dekoratören fungerar inte direkt på utlösarens startpunktsmetod main() . Du måste skapa underfunktioner och dekorera dem. På grund av ett känt problem med minnesprofilering är coroutine-returvärdet alltid när Nonedet gäller en asynkron koroutin.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Testa minnesprofileraren på den lokala datorn med hjälp av kommandot func host startAzure Functions Core Tools . När du anropar funktionerna bör de generera en minnesanvändningsrapport. Rapporten innehåller filnamn, kodrad, minnesanvändning, minnesökning och radinnehåll i den.

  5. Om du vill kontrollera minnesprofileringsloggarna på en befintlig funktionsappinstans i Azure kan du fråga minnesprofileringsloggarna efter de senaste anropen med Kusto-frågor i Application Insights, Loggar.

    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
    

Exempel

Här är ett exempel på hur du utför minnesprofilering på en asynkron och en synkron HTTP-utlösare med namnet "HttpTriggerAsync" respektive "HttpTriggerSync". Vi skapar en Python-funktionsapp som helt enkelt skickar ut GET-begäranden till Microsofts startsida.

Skapa en Python-funktionsapp

En Python-funktionsapp bör följa den angivna mappstrukturen i Azure Functions. För att skapa en autogenerering av projektet rekommenderar vi att du använder Azure Functions Core Tools genom att köra följande kommandon:

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

Uppdatera filinnehåll

Requirements.txt definierar de paket som används i vårt projekt. Förutom Azure Functions SDK och memory-profiler introducerar aiohttp vi för asynkrona HTTP-begäranden och requests synkrona HTTP-anrop.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Skapa den asynkrona HTTP-utlösaren.

Ersätt koden i den asynkrona HTTP-utlösaren HttpTriggerAsync/__init__.py med följande kod, som konfigurerar minnesprofilering, rotloggningsformat och loggningsströmningsbindning.

# 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

Skapa den synkrona HTTP-utlösaren.

Ersätt koden i den asynkrona HTTP-utlösaren HttpTriggerSync/__init__.py med följande kod.

# 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

Profilera Python-funktionsapp i lokal utvecklingsmiljö

När du har gjort ändringarna ovan finns det några steg till för att initiera en virtuell Python-miljö för Azure Functions-körning.

  1. Öppna en Windows PowerShell eller ett Linux-gränssnitt som du föredrar.

  2. Skapa en virtuell Python-miljö py -m venv .venv i Windows eller python3 -m venv .venv i Linux.

  3. Aktivera den virtuella Python-miljön med .venv\Scripts\Activate.ps1 i Windows PowerShell eller source .venv/bin/activate i Linux-gränssnittet.

  4. Återställa Python-beroenden med pip install -r requirements.txt

  5. Starta Azure Functions-körningen lokalt med Azure Functions Core Tools func host start

  6. Skicka en GET-begäran till https://localhost:7071/api/HttpTriggerAsync eller https://localhost:7071/api/HttpTriggerSync.

  7. Den bör visa en minnesprofileringsrapport som liknar följande avsnitt i 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()
    

Nästa steg

Mer information om Azure Functions Python-utveckling finns i följande resurser: