Profilowanie użycia pamięci aplikacji w języku Python w usłudze Azure Functions

Podczas tworzenia lub po wdrożeniu lokalnego projektu aplikacji funkcji w języku Python do platformy Azure dobrą praktyką jest przeanalizowanie funkcji pod kątem potencjalnych wąskich gardeł związanych z pamięcią. Takie wąskie gardła mogą zmniejszyć wydajność Twoich funkcji i prowadzić do błędów. Poniższe instrukcje pokazują, jak korzystać z pakietu Python memory-profiler, który zapewnia analizę zużycia pamięci w poszczególnych wierszach przez funkcje podczas ich wykonywania.

Uwaga

Profilowanie pamięci jest przeznaczone tylko do analizy śladu pamięci w środowiskach deweloperskich. Nie należy stosować profilera pamięci w aplikacjach funkcji produkcyjnych.

Wymagania wstępne

Przed rozpoczęciem tworzenia aplikacji funkcji języka Python należy spełnić następujące wymagania:

Jeśli nie masz jeszcze konta platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.

Proces profilowania pamięci

  1. W pliku requirements.txt dodaj memory-profiler, aby upewnić się, że pakiet zostanie dołączony do wdrożenia. Jeśli tworzysz oprogramowanie na komputerze lokalnym, możesz chcieć aktywować wirtualne środowisko Pythona i rozwiązać zależności pakietów za pomocą pip install -r requirements.txt.

  2. W skrywcie funkcji (na przykład __init__.py dla modelu programowania Python w wersji 1 i function_app.py dla modelu w wersji 2 dodaj następujące wiersze powyżej main() funkcji. Te wiersze zapewniają, że główny rejestrator raportuje nazwy podrzędnego rejestratora, aby dzienniki profilowania pamięci były rozróżniane przez prefiks 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. Zastosuj następujący dekorator powyżej wszystkich funkcji wymagających profilowania pamięci. Dekorator nie działa bezpośrednio na metodzie wejściowej wyzwalacza main(). Musisz utworzyć funkcje podrzędne i udekorować je. Ponadto, ze względu na znany problem z profilerem pamięci, przy stosowaniu go do asynchronicznej procedury współbieżnej zwracana wartość zawsze ma postać None.

    @memory_profiler.profile(stream=profiler_logstream)
    
  4. Przetestuj profiler pamięci na komputerze lokalnym przy użyciu polecenia func host startAzure Functions Core Tools . Podczas wywoływania funkcji powinny one generować raport użycia pamięci. Raport zawiera nazwę pliku, wiersz kodu, użycie pamięci, przyrost pamięci i zawartość wiersza w nim.

  5. Aby sprawdzić dzienniki profilowania pamięci w istniejącym wystąpieniu aplikacji funkcji na platformie Azure, możesz wykonać zapytanie dotyczące dzienników profilowania pamięci pod kątem ostatnich wywołań za pomocą zapytań Kusto w usłudze Application Insights, logs.

    Zrzut ekranu przedstawiający użycie pamięci zapytania aplikacji w języku Python w usłudze 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
    

Przykład

Oto przykład wykonywania profilowania pamięci na asynchronicznym i synchronicznym wyzwalaczu HTTP o nazwach "HttpTriggerAsync" i "HttpTriggerSync". Utworzymy aplikację funkcji języka Python, która po prostu wysyła żądania GET na stronę główną firmy Microsoft.

Utwórz aplikację funkcji Python

Aplikacja funkcji języka Python powinna być zgodna z określoną strukturą folderów usługi Azure Functions. W celu tworzenia szkieletu projektu zalecamy użycie narzędzi Azure Functions Core Tools, uruchamiając następujące polecenia:

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

Aktualizowanie zawartości pliku

Requirements.txt definiuje pakiety używane w naszym projekcie. Oprócz zestawu SDK usługi Azure Functions i profilera pamięci, wprowadzamy aiohttp do asynchronicznych żądań HTTP oraz requests do synchronicznych wywołań HTTP.

# requirements.txt

azure-functions
memory-profiler
aiohttp
requests

Utwórz asynchroniczny wyzwalacz HTTP.

Zastąp kod w asynchronicznym wyzwalaczu HTTP HttpTriggerAsync/__init__.py następującym kodem, który konfiguruje profiler pamięci, format głównego loggera oraz powiązanie strumieniowania loggera.

# 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

Utwórz synchroniczny wyzwalacz HTTP.

Zastąp kod w asynchronicznym wyzwalaczu HTTP HttpTriggerSync/__init__.py następującym kodem.

# 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

Profilowanie aplikacji funkcji Python w lokalnym środowisku programistycznym

Po wprowadzeniu powyższych zmian istnieje jeszcze kilka kroków inicjowania środowiska wirtualnego języka Python dla środowiska uruchomieniowego usługi Azure Functions.

  1. Otwórz Windows PowerShell lub dowolną powłokę systemu Linux, zależnie od preferencji.

  2. Utwórz środowisko wirtualne języka Python według py -m venv .venv w systemie Windows lub python3 -m venv .venv w systemie Linux.

  3. Aktywuj wirtualne środowisko Pythona za pomocą .venv\Scripts\Activate.ps1 w Windows PowerShell lub source .venv/bin/activate w powłoce systemu Linux.

  4. Przywracanie zależności języka Python za pomocą polecenia pip install -r requirements.txt

  5. Lokalne uruchamianie środowiska uruchomieniowego usługi Azure Functions przy użyciu narzędzi Azure Functions Core Tools func host start

  6. Wyślij żądanie GET do https://localhost:7071/api/HttpTriggerAsync lub https://localhost:7071/api/HttpTriggerSync.

  7. Powinien zostać wyświetlony raport profilowania pamięci podobny do poniższej sekcji w narzędziach 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()
    

Następne kroki

Aby uzyskać więcej informacji na temat programowania w języku Python w usłudze Azure Functions, zobacz następujące zasoby: