Gunicornで実行されているFlask-SQLAlchemyアプリのDB pool_sizeの選択


8

Gunicornで実行中のFlask-SQLAlchmeyアプリをPostgreSQLデータベースに接続していて、そのpool_size値が何であるか、また予想されるデータベース接続の数を見つけるのに苦労しています。

これは、物事がどのように機能するかについての私の理解です:

  • Python 3.7のプロセスはメモリを共有しない
  • 各Gunicornワーカーは独自のプロセスです
  • したがって、各Gunicornワーカーは、データベース接続プールの独自のコピーを取得し、他のワーカーと共有されません。
  • Pythonのスレッドはメモリを共有します
  • したがって、Gunicornワーカー内のすべてのスレッドは、データベース接続プールを共有します

これまでのところ正しいですか?それが正しい場合、Gunicornで実行されている同期Flaskアプリの場合:

  • データベース接続の最大数=(ワーカー数)*(ワーカーあたりのスレッド数)?
  • そして、ワーカー内で、ワーカーよりもプールからの接続を多く使用しますか?

pool_sizeスレッド数よりも大きくする必要がある理由はありますか?だから、で起動したgunicornアプリの場合は2 でgunicorn --workers=5 --threads=2 main:appなければpool_sizeなりませんか?また、ワーカーを使用し、スレッドを使用していないpool_size場合、1より大きい値を使用する理由はありますか?

回答:


3

私の2セントを追加します。あなたの理解は正しいですが、考慮すべきいくつかの考え:

  • アプリケーションがIOにバインドされている場合(データベースと通信している場合など)は、実際には複数のスレッドが必要です。それ以外の場合、CPUは使用率の100%に達しません。適切な量​​を得るには、通常、負荷テストツールを使用して、1秒あたりのリクエスト数とCPU使用率を比較するスレッド数を試してみる必要があります。

  • ワーカーの数と接続の関係を考慮して、ワーカーの数を変更するときは、最大プールサイズを調整する必要があることがわかります。これは忘れがちですので、プールのサイズをワーカーの数より少し上、たとえばその数の2倍に設定することをお勧めします。

  • 多くのgunicornプロセスがある場合、postgresqlは接続ごとにプロセスを作成し、適切にスケーリングしない可能性があります。アプリとデータベースの間にある接続プールを使用します(おそらくpgbouncerが最も人気があると思います)。


3

@matinoの回答に私の最近の経験の一部を追加するだけです。WSGIアプリケーションは非同期ワーカーからも恩恵を受けることができます。async workersconnection poolsここにいくつかのポイントを追加します。

私たちは最近、生産に関していくつかの同様の問題に直面しました。私たちのトラフィックは1〜2日でスカイジャンプし、何らかの理由ですべてのリクエストが詰まっていました。アプリケーションでは、gevent非同期ワーカーでgunicornを使用していましたdjango。判明したpsql接続が、リクエストの多くが停止した(そして最終的にはタイムアウトした)理由でした。

推奨される同時リクエスト(2*CPU)+1です。したがって、同期シナリオでは、計算は次のようになります。(workers_num * threads_num) <= (2 * cores_num) + 1

そして、あなたは(workers_num * threads_num)あなたのデータベースへの最大接続を取得します。(たとえば、すべてのリクエストにdbクエリがあります)。したがって、psql pool_size設定をこの数値より大きい値に設定する必要があります。ただし、非同期ワーカーを使用する場合、計算は少し異なります。次のgunicornコマンドを見てください。

gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 django:app

この場合、同時リクエストの最大数は、リクエストまで可能です3000。したがって、pool_sizeをより大きい値に設定する必要があります3000。アプリケーションがIOバウンドの場合、非同期ワーカーを使用するとパフォーマンスが向上します。これにより、CPUをより効率的に使用できるようになります。

また、接続プールについて、のようなソリューションを使用するPgBouncerと、接続を常に開いたり閉じたりするオーバーヘッドがなくなります。したがって、の設定に関する決定には影響しませんpool_size。トラフィックが少ない場合、その影響は目立たない可能性がありますが、より高いトラフィックレートを処理するためには必要です。


2

あなたの理解はかなり良いと思います。単一のWSGIワーカー内のスレッドは実際に接続プールを共有します。したがって、理論的にデータベース接続の最大数である(number of workers) * N場合N = pool_size + max_overflow。(Flask-SQLAlchemyがmax_overflowを何に設定するかはわかりませんが、ここでの方程式の重要な部分です- それが何を意味するかについては、QueuePoolのドキュメントを参照してください。)

実際には、Flask-SQLAlchemyによって提供されるスレッドスコープのセッションのみを使用する場合、スレッドごとに最大1つの接続が存在します。したがって、スレッド数がNそれより少ない場合、上限は確かにになります(number of workers) * (number of threads per worker)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.