継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

FastAPI と Falcon を Docker イメージにした時のサイズとレスポンスのスピードを計測した

タダです.

業務で API で使用する言語を置き換える検討をしていたりするんですが, FastAPI と Falcon を比較した際Docker イメージにした時の軽量さとベンチマークしてみてどれくらいレスポンスが速いかを計測した機会があったので,この記事に検証した内容をまとめておきます.

FastAPI と Falcon の特徴

2つの Web フレームワークがどのような特徴を持っているかをさらっておきます.FastAPI は Python 3.6 以上の速い Web フレームワークであると謳ってます.また,ASGI を使います.

FastAPI fastapi.tiangolo.com

特徴としては次のようなものがあります.

・ 速い。非常に高性能で、NodeJSやGoと同等のパフォーマンスを発揮します(StarletteとPydanticのおかげです)。利用可能なPythonフレームワークの中で最も高速なものの一つです。

・コード化が速い。機能開発のスピードを約200%~300%向上させます。

・バグが少ない。人間(開発者)によるエラーを約40%削減。

・ 直感的。素晴らしいエディタサポート。デバッグ時間を短縮。

・ 簡単。使いやすく、学習しやすいように設計されています。ドキュメントを読む時間を短縮。

・ 短い。コードの重複を最小限に抑えます。各パラメータ宣言から複数の機能を利用できるようになっています。

・ 堅牢。すぐに使えるコードを取得できます。自動でインタラクティブなドキュメントを提供します。

・ 標準ベース。APIのオープンスタンダードに基づいています(完全に互換性があります)。OpenAPI(以前はSwaggerとして知られていた)とJSON Schema。

Falcon も速く,軽量な Web フレームワークです. WSGI を使います.

Falcon falcon.readthedocs.io

特徴としては次のようなものがあります.

URIテンプレートRFCに基づくルート

・リソースへのURIのRESTに触発されたマッピング

・グローバル、リソース、およびメソッドのフック

・慣用的なHTTPエラー応答

Unicodeの完全サポート

・直感的なリクエストオブジェクトとレスポンスオブジェクト

・geventのような非同期ライブラリでうまく機能します

・安全なAPIを作成するための最小限の攻撃対象領域

・包括的なテストスイートで100%のコードカバレッジ

・他のPythonパッケージへの依存関係はありません

Python 2.7、3.5以降をサポート

・PyPyと互換性があります

Docker イメージ化した時のサイズ

Alphine Linux ベースの Docker イメージでビルドした場合のサイズですが,2つとも同じくらいのサイズ感でした.

# Falcon
$ docker images | grep falcon
falcon                                     latest              c74c32855823        About a minute ago   49.2MB
# FastAPI
$ docker images | grep fastapi
fastapi                      latest              88fd7ac8fa13        3 hours ago          50.1MB

どれくらい早くレスポンスがされるかのベンチマーク

wrk2 を使って以下の条件でベンチマークしてみました.

  • プログラムは Hello World を返すもの
  • 30 秒間で固定してベンチマークをする
  • 秒間100,500,1000,5000,10000 リクエストを投げてその結果を確認する

10のコネクションを維持して、秒間 100 リクエスト投げた時の計測

FastAPI,Falcon ともに大きな差異はない.

# FastAPI
wrk2 -t2 -c10 -d30s -R100 http://localhost:8000/
Running 30s test @ http://localhost:8000/
  2 threads and 10 connections
  Thread calibration: mean lat.: 7.524ms, rate sampling interval: 25ms
  Thread calibration: mean lat.: 7.752ms, rate sampling interval: 26ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.06ms    3.00ms  22.78ms   79.35%
    Req/Sec    53.01     71.93   208.00     80.30%
  3002 requests in 30.01s, 416.29KB read
Requests/sec:    100.02
Transfer/sec:     13.87KB

# Falcon
wrk2 -t2 -c10 -d30s -R100 http://localhost:8080/
Running 30s test @ http://localhost:8080/
  2 threads and 10 connections
  Thread calibration: mean lat.: 32.647ms, rate sampling interval: 209ms
  Thread calibration: mean lat.: 20.032ms, rate sampling interval: 185ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     6.24ms    4.06ms  29.98ms   82.81%
    Req/Sec    49.44      5.69    62.00     84.00%
  3002 requests in 30.01s, 483.72KB read
Requests/sec:    100.03
Transfer/sec:     16.12KB

50のコネクションを維持して、秒間 500 リクエスト投げた時の計測

Latency で FastAPI と Falcon の間に差がでてきた.

# FastAPI
wrk2 -t2 -c50 -d30s -R500 http://localhost:8000/
Running 30s test @ http://localhost:8000/
  2 threads and 50 connections
  Thread calibration: mean lat.: 7.982ms, rate sampling interval: 28ms
  Thread calibration: mean lat.: 7.915ms, rate sampling interval: 27ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.11ms    2.25ms  19.73ms   81.05%
    Req/Sec   254.29     63.28   423.00     61.43%
  14991 requests in 30.00s, 2.03MB read
Requests/sec:    499.66
Transfer/sec:     69.29KB

# Falcon
wrk2 -t2 -c50 -d30s -R500 http://localhost:8080/
Running 30s test @ http://localhost:8080/
  2 threads and 50 connections
  Thread calibration: mean lat.: 46.716ms, rate sampling interval: 204ms
  Thread calibration: mean lat.: 45.854ms, rate sampling interval: 200ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    14.29ms   20.81ms 135.04ms   88.48%
    Req/Sec   250.44      6.95   280.00     80.10%
  14991 requests in 30.00s, 2.36MB read
Requests/sec:    499.63
Transfer/sec:     80.51KB

100のコネクションを維持して、秒間 1000 リクエスト投げた時の計測

1000リクエストになったら Requests を捌く量も Latency と同じくひらいてきた.

# FastAPI
 wrk2 -t2 -c100 -d30s -R1000 http://localhost:8000/
Running 30s test @ http://localhost:8000/
  2 threads and 100 connections
  Thread calibration: mean lat.: 241.727ms, rate sampling interval: 819ms
  Thread calibration: mean lat.: 240.797ms, rate sampling interval: 815ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   241.60ms  260.77ms 777.22ms   75.42%
    Req/Sec   481.31     47.68   583.00     79.17%
  29201 requests in 30.01s, 3.96MB read
Requests/sec:    973.16
Transfer/sec:    135.12KB

# Falcon
wrk2 -t2 -c100 -d30s -R1000 http://localhost:8080/
Running 30s test @ http://localhost:8080/
  2 threads and 100 connections
  Thread calibration: mean lat.: 124.110ms, rate sampling interval: 383ms
  Thread calibration: mean lat.: 124.684ms, rate sampling interval: 393ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   527.57ms  528.20ms   1.86s    73.48%
    Req/Sec   161.29    255.12     0.99k    71.57%
  16458 requests in 30.27s, 2.59MB read
  Socket errors: connect 0, read 0, write 0, timeout 600
Requests/sec:    543.71
Transfer/sec:     87.61KB

500のコネクションを維持して、秒間 5000 リクエスト投げた時の計測

# FastAPI
wrk2 -t2 -c500 -d30s -R5000 http://localhost:8000/
Running 30s test @ http://localhost:8000/
  2 threads and 500 connections
  Thread calibration: mean lat.: 3006.903ms, rate sampling interval: 11796ms
  Thread calibration: mean lat.: 3028.214ms, rate sampling interval: 11796ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.31s     3.42s   18.87s    58.52%
    Req/Sec   456.00     68.00   524.00    100.00%
  26269 requests in 30.01s, 3.56MB read
  Socket errors: connect 251, read 64, write 0, timeout 3514
Requests/sec:    875.44
Transfer/sec:    121.59KB

# Falcon
wrk2 -t2 -c500 -d30s -R5000 http://localhost:8080/
Running 30s test @ http://localhost:8080/
  2 threads and 500 connections
  Thread calibration: mean lat.: 2613.849ms, rate sampling interval: 10739ms
  Thread calibration: mean lat.: 2724.868ms, rate sampling interval: 10936ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.13s     2.36s   15.61s    65.29%
    Req/Sec   275.50     29.50   305.00    100.00%
  16381 requests in 31.28s, 2.58MB read
  Socket errors: connect 251, read 153, write 0, timeout 5439
Requests/sec:    523.76
Transfer/sec:     84.39KB

1000のコネクションを維持して、秒間 10000 リクエスト投げた時の計測

# FastAPI
wrk2 -t2 -c1000 -d30s -R10000 http://localhost:8000/
Running 30s test @ http://localhost:8000/
  2 threads and 1000 connections
  Thread calibration: mean lat.: 3875.593ms, rate sampling interval: 13352ms
  Thread calibration: mean lat.: 3795.580ms, rate sampling interval: 13303ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.20s     3.03s   18.14s    57.44%
    Req/Sec   514.50     39.50   554.00    100.00%
  27956 requests in 30.00s, 3.79MB read
  Socket errors: connect 751, read 0, write 0, timeout 9763
Requests/sec:    931.79
Transfer/sec:    129.26KB

# Falcon
wrk2 -t2 -c1000 -d30s -R10000 http://localhost:8080/
Running 30s test @ http://localhost:8080/
  2 threads and 1000 connections
  Thread calibration: mean lat.: 3676.434ms, rate sampling interval: 14540ms
  Thread calibration: mean lat.: 3547.812ms, rate sampling interval: 14319ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.69s     2.42s   17.81s    67.25%
    Req/Sec   155.50      5.50   161.00    100.00%
  16445 requests in 30.53s, 2.59MB read
  Socket errors: connect 751, read 45, write 0, timeout 12373
Requests/sec:    538.65

Docker イメージにした時のサイズとベンチマークを踏まえての所感

検証の結果を踏まえて次の感想を持ちました.

  • Docker イメージにした時の軽量さは2つに大差はない
  • リクエスト数が増えていった時も FastAPI のほうが処理スピードが速くリクエストを捌く量も多い

また, FastAPI のドキュメントをみていると,FastAPI を作る時に既存のフレームワークを参考に開発したと解説されており, Falcon も参考にして開発されているようなので改良されたのが FastAPI って位置付けなのだと感じました.

fastapi.tiangolo.com

まとめ

FastAPI と Falcon の比較をするための検証で行ったことを整理してみました.ベンチマークしてみて FastAPI が速くてパフォーマンスも優れているという所以を感じることができました.FastAPI を業務で使う機会が出てきたら習熟していけるようになっていきたいです.