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

Podczas programowania lub po wdrożeniu lokalnego projektu aplikacji funkcji języka Python na platformie Azure warto przeanalizować potencjalne wąskie gardła pamięci w funkcjach. Takie wąskie gardła mogą zmniejszyć wydajność funkcji i prowadzić do błędów. Poniższe instrukcje pokazują, jak używać pakietu języka Python profilera pamięci, który zapewnia analizę zużycia pamięci po wierszu funkcji 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 subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto platformy Azure.

Proces profilowania pamięci

  1. W pliku requirements.txt dodaj plik memory-profiler , aby upewnić się, że pakiet jest powiązany z wdrożeniem. Jeśli programujesz na komputerze lokalnym, możesz aktywować środowisko wirtualne języka Python i wykonać rozwiązanie pakietu przez pip install -r requirements.txtpolecenie .

  2. W skrycie funkcji (na przykład __init__.py dla modelu programowania w języku 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 w metodzie punktu wejścia main() wyzwalacza. Musisz utworzyć funkcje podrzędne i udekorować je. Ponadto ze względu na znany problem z profilerem pamięci podczas stosowania do asynchronicznego coroutine wartość zwracana jest zawsze 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 Szczegółowe informacje, 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
    

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.

Tworzenie aplikacji funkcji języka 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

Plik requirements.txt definiuje pakiety używane w naszym projekcie. Oprócz zestawu SDK usługi Azure Functions i profilera pamięci wprowadzamy aiohttp obsługę asynchronicznych żądań HTTP i requests 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 rejestratora i powiązanie przesyłania strumieniowego rejestratora.

# 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 języka Python w lokalnym środowisku projektowym

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 program Windows PowerShell lub dowolną powłokę systemu Linux w preferowany sposób.

  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 środowisko wirtualne języka Python za pomocą .venv\Scripts\Activate.ps1 programu Windows PowerShell lub source .venv/bin/activate powłoki 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: