Erstellen eines Profils der Arbeitsspeichernutzung für Python-Apps in Azure Functions

Bei der Entwicklung oder nach der Bereitstellung Ihres lokalen Python-Funktions-App-Projekts in Azure sollten Sie analysieren, ob Ihre Funktionen potenzielle Arbeitsspeicherengpässe aufweisen. Solche Engpässe können die Leistung Ihrer Funktionen beeinträchtigen und zu Fehlern führen. Die folgenden Anweisungen zeigen Ihnen, wie Sie das Python-Paket memory-profiler verwenden, das den Speicherverbrauch Ihrer Funktionen während der Ausführung Zeile für Zeile analysiert.

Hinweis

Die Speicherprofilerstellung ist nur für die Analyse des Speicherbedarfs in Entwicklungsumgebungen vorgesehen. Wenden Sie den Arbeitsspeicherprofiler nicht auf Produktionsfunktions-Apps an.

Voraussetzungen

Bevor Sie mit der Entwicklung einer Python-Funktions-App beginnen, müssen Sie die folgenden Anforderungen erfüllen:

Sollten Sie über kein Azure-Abonnement verfügen, können Sie zunächst ein kostenloses Azure-Konto erstellen.

Der Prozess der Arbeitsspeicher-Profilerstellung

  1. Fügen Sie in Ihrer Datei „requirements.txt“ memory-profiler hinzu, um sicherzustellen, dass das Paket mit Ihrer Bereitstellung gebündelt wird. Wenn Sie die Entwicklung auf dem lokalen Computer vornehmen, könnten Sie eine virtuelle Python-Umgebung aktivieren und eine Paketauflösung mit pip install -r requirements.txt durchführen.

  2. Fügen Sie in Ihrem Funktionsskript (z. B. __init__.py für das Python v1-Programmiermodell und function_app.py für das v2-Modell) die folgenden Zeilen über der Funktion main() hinzu. Durch diese Zeilen wird sichergestellt, dass die Stammprotokollierung die Namen der untergeordneten Protokollierung meldet, damit die Protokolle der Speicherprofilerstellung durch das Präfix memory_profiler_logs unterschieden werden können.

    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. Wenden Sie den folgenden Decorator über allen Funktionen an, für die eine Speicherprofilierung erforderlich ist. Dieser Decorator funktioniert nicht direkt über die Trigger-Einstiegspunktmethode main(). Sie müssen hierzu Unterfunktionen mit einem Decorator erstellen. Auch ist der Rückgabewert der Coroutine beim Anwenden auf eine asynchrone Coroutine aufgrund eines bekannten Problems bei der Speicherprofilerstellung immer None.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Überprüfen Sie die Speicherprofilerstellung auf Ihrem lokalen Computer mithilfe des Azure Functions Core Tools-Befehls func host start. Wenn Sie die Funktionen aufrufen, sollten sie einen Bericht zur Speicherauslastung generieren. Der Bericht enthält Dateiname, Codezeile, Speicherauslastung, Speicherinkrement und den darin enthaltenen Zeileninhalt.

  5. Die Protokolle der Speicherprofilerstellung der letzten Aufrufe einer vorhandenen Funktions-App-Instanz können Sie in Azure mit den folgenden Kusto-Abfragen in Application Insights (Protokolle) überprüfen.

    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
    

Beispiel

Hier ist ein Beispiel für die Durchführung der Speicherprofilerstellung auf einem asynchronen und einem synchronen HTTP-Trigger mit den Namen „HttpTriggerAsync“ und „HttpTriggerSync“. Wir erstellen eine Python-Funktions-App, die einfach GET-Anforderungen an die Homepage von Microsoft sendet.

Erstellen einer Python-Funktions-App

Eine Python-Funktions-App sollte die von Azure Functions vorgegebene Ordnerstruktur berücksichtigen. Sie sollten Azure Functions Core Tools als Gerüst des Projekts verwenden, indem Sie die folgenden Befehle ausführen:

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

Aktualisieren des Dateiinhalts

Die Datei requirements.txt definiert die Pakete, die in unserem Projekt verwendet werden. Neben dem Azure Functions SDK und dem Arbeitsspeicherprofiler werden aiohttp für asynchrone HTTP-Anforderungen und requests für synchrone HTTP-Aufrufe eingeführt.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Erstellen Sie den asynchronen HTTP-Trigger.

Ersetzen Sie den Code im asynchronen HTTP-Trigger HttpTriggerAsync/__init__.py durch den folgenden Code, der die Speicherprofilerstellung, das Stammprotokollierungsformat und die Protokollierungsstreamingbindung konfiguriert.

# 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

Erstellen Sie den synchronen HTTP-Trigger.

Ersetzen Sie den Code im asynchronen HTTP-Trigger HttpTriggerSync/__init__.py durch den folgenden Code.

# 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

Profilerstellung für Python-Funktions-Apps in lokaler Entwicklungsumgebung

Nachdem Sie alle oben genannten Änderungen vorgenommen haben, sind einige weitere Schritte erforderlich, um eine virtuelle Python-Umgebung für die Azure Functions-Runtime zu initialisieren.

  1. Öffnen Sie nach Wunsch eine Windows PowerShell-Instanz oder eine beliebige Linux-Shell.

  2. Erstellen Sie eine virtuelle Python-Umgebung mit py -m venv .venv unter Windows oder python3 -m venv .venv unter Linux.

  3. Aktivieren Sie die virtuelle Python-Umgebung mit .venv\Scripts\Activate.ps1 in Windows PowerShell oder mit source .venv/bin/activate in der Linux-Shell.

  4. Wiederherstellen der Python-Abhängigkeiten mit pip install -r requirements.txt

  5. Starten Sie die Azure Functions-Runtime lokal mit func host start Azure Functions Core Tools.

  6. Senden Sie eine GET-Anforderung an https://localhost:7071/api/HttpTriggerAsync oder https://localhost:7071/api/HttpTriggerSync.

  7. Es sollte ein Bericht zur Speicherprofilerstellung angezeigt werden, der dem folgenden Abschnitt in Azure Functions Core Tools ähnelt.

    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ächste Schritte

Weitere Informationen zur Python-Entwicklung für Azure Functions finden Sie in den folgenden Ressourcen: