分析 Azure Functions Python 应用的内存用量
在开发过程中或在将本地 Python 函数应用项目部署到 Azure 之后,最好分析函数中的潜在内存瓶颈。 此类瓶颈会削弱函数性能并导致错误。 以下说明演示了如何使用内存探查器 Python 包,其在执行时逐行分析函数的内存消耗。
注意
内存分析仅适用于开发环境的内存占用情况分析。 请不要在生产函数应用中使用内存探查器。
先决条件
开发 Python 函数应用必须满足以下要求:
Python 3.7 或更高版本。 若要查看 Azure Functions 支持的 Python 版本的完整列表,请参阅 Python 开发人员指南。
Azure Functions Core Tools 版本 4.x 或更高版本。 使用
func --version
检查版本。 若要了解如何更新,请参阅 GitHub 上的 Azure Functions Core Tools。已在某个支持的平台上安装 Visual Studio Code。
一个有效的 Azure 订阅。
如果没有 Azure 订阅,可在开始前创建一个试用帐户。
内存分析过程
在 requirements.txt 中添加
memory-profiler
,确保将包与部署捆绑在一起。 如果在本地计算机上开发,则可能需要激活 Python 虚拟环境,并使用pip install -r requirements.txt
进行包解析。例如,在函数脚本(对于 Python v1 编程模型为 __init__.py,对于 v2 模型为 function_app.py)中,在
main()
函数上方添加以下行。 这些行确保根记录器报告子记录器名称,以便通过前缀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)
在需要内存分析的任何函数上应用以下修饰器。 修饰器不直接在触发器入口点
main()
方法上工作。 需要创建子函数并修饰它们。 此外,由于内存探查器的已知问题,在应用于异步协同例程时,协同例程返回值始终为None
。@memory_profiler.profile(stream=profiler_logstream)
使用 Azure Functions Core Tools 命令
func host start
在本地计算机上测试内存探查器。 调用函数时,它们应生成内存使用情况报告。 该报告包含文件名、代码行、内存使用情况、内存增量以及其中的行内容。若要检查 Azure 中现有函数应用实例上的内存分析日志,可以通过 Application Insights、Logs 中的 Kusto 查询来查询最近调用的内存分析日志。
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
示例
以下示例解释了如何对异步和同步 HTTP 触发器(分别名为“HttpTriggerAsync”和“HttpTriggerSync”)执行内存分析。 我们将创建仅向 Microsoft 主页发送 GET 请求的 Python 函数应用。
创建 Python 函数应用
Python 函数应用应沿用 Azure Functions 指定的 文件夹结构。 若要创建项目基架,建议通过运行以下命令使用 Azure Functions Core Tools:
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
更新文件内容
requirements.txt 定义我们的项目使用的包。 除了 Azure Functions SDK 和内存探查器外,我们还介绍了异步 HTTP 请求的aiohttp
与同步 HTTP 调用的requests
。
# requirements.txt
azure-functions
memory-profiler
aiohttp
requests
创建异步 HTTP 触发器。
将异步 HTTP 触发器 HttpTriggerAsync/__init__.py 中的代码替换为以下代码,用于配置内存探查器、根记录器格式和记录器流绑定。
# 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
创建同步 HTTP 触发器。
将异步 HTTP 触发器 HttpTriggerSync/__init__.py 中的代码替换为以下代码。
# 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
分析本地开发环境中的 Python 函数应用
进行上述更改后,还需几个步骤即可为 Azure Functions 运行时初始化 Python 虚拟环境。
根据喜好打开 Windows PowerShell 或任何 Linux shell。
通过 Windows 的
py -m venv .venv
或 Linux 的python3 -m venv .venv
创建 Python 虚拟环境。通过 Windows PowerShell 的
.venv\Scripts\Activate.ps1
或 Linux shell 的source .venv/bin/activate
激活 Python 虚拟环境。通过
pip install -r requirements.txt
还原 Python 依赖项通过 Azure Functions Core Tools
func host start
启动本地 Azure Functions runtime 运行时将 GET 请求发送至
https://localhost:7071/api/HttpTriggerAsync
或https://localhost:7071/api/HttpTriggerSync
。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()
后续步骤
有关 Azure Functions Python 开发的详细信息,请参阅以下资源: