コンテンツにスキップ

FastAPI のプロファイリング

Python で WebAPI を開発する際は、個人的に FastAPI を使うことが多い。WebAPI のパフォーマンスをチューニングしたい場面が何度かあり、そのためのプロファイリング方法を調べたので備忘録として残しておく。

プロファイリングの方法

私が観測している範囲では、次のようなツールでプロファイリングできる。

今回メインで取り上げるのは fastapi_profiler である。他の二つについて軽く触れておくと、logfire は pydantic チームが開発しているサービス。logfire のサービスに OpenTelemetry を使ってデータを送信することで、リクエストのトレースができる。 Pydantic との統合や FastAPI 以外にも OpenAI のフレームワークとも連携できる。2024/05/03 時点ではベータ版となっており無料で利用できる。 OpenTelemetry は、分散トレーシングのためのプロジェクトで、FastAPI にも導入できる。各クラウドプロバイダーのサービスとも連携できる。

fastapi_profiler

fastapi_profiler は FastAPI 用のプロファイリングツールで、FastAPI のリクエストに対してプロファイリングできる。リクエストごとの処理時間やメモリ使用量、各 Python コードの処理時間を計測できる。FastAPI のミドルウェアとして提供されている。

インストール

pip install fastapi_profiler

使い方

FastAPI のミドルウェアとして PyInstrumentProfilerMiddleware を追加するだけで利用できる。

import time

import uvicorn
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi_profiler import PyInstrumentProfilerMiddleware

app = FastAPI()
app.add_middleware(PyInstrumentProfilerMiddleware)


@app.get("/test")
async def normal_request():
    time.sleep(1)
    return JSONResponse({"retMsg": "Hello World!"})


if __name__ == '__main__':
    uvicorn.run(app=app, host="0.0.0.0", port=8080, workers=1)

/test にリクエストを送信すると、以下のようなログが出力される。

INFO:     127.0.0.1:54872 - "GET /test HTTP/1.1" 200 OK
Method: GET, Path: /test, Duration: 1.0088946190662682, Status: 200

  _     ._   __/__   _ _  _  _ _/_   Recorded: 07:11:39  Samples:  83
 /_//_/// /_\ / //_// / //_'/ //     Duration: 1.009     CPU time: 0.009
/   _/                      v4.6.2

Program: /tmp/pants-sandbox-ETDYpC/sandbox/fastapi-profiler/app.py

1.009 PyInstrumentProfilerMiddleware.__call__  fastapi_profiler/profiler.py:66
`- 1.009 ExceptionMiddleware.__call__  starlette/middleware/exceptions.py:49
      [10 frames hidden]  starlette, fastapi
         1.001 run_endpoint_function  fastapi/routing.py:183
         `- 1.001 normal_request  sandbox/fastapi-profiler/app.py:14
            `- 1.000 sleep  <built-in>

今回の例は簡単なものだが、複雑な処理を行っている場合は、各関数や行レベルで計測してくれるので、ボトルネックを特定するのに便利。 設定次第で html や json で出力することもできる。