コネクションプール(Connection Pool)
コネクションプールという技術は DB 接続クライアント側の技術です。なので PostgreSQL や MySQL 等の DB サーバにその機能があるわけではありません。
DB クライアントがコネクションプール機能を使うと、クエリーが必要になる前に DB へ複数の接続手続きを済ませておき、コネクションを確立し維持させておくことができます。
これにより、いざクエリーが必要になったときに低コスト、低遅延が期待できます。(この機能が無い場合はクエリーが必要になったタイミングで DB への認証から始まる接続手続きが必要になり、そしてクエリーが終わった後は切断手続きが必要になります。)
Django の持続的接続 (Persistent Connections)
Django は DB クライアントになりますが、Django は標準でコネクションプール機能は持っていません。
似た機能として持続的接続 (Persistent Connections) という機能があります。
これは事前に接続する、というわけではなく、必要になったタイミングで接続を確立しますが、一定時間、その接続を維持し、使い回しします。
維持する時間は settings.py の DATABASES の中の CONN_MAX_AGE (秒) で定義します。デフォルト値は 0 なので、この設定をしていない場合は、DB アクセスを要するリクエストのたびに DB 接続を開始し、レスポンスが返った後は切断手続きが為されます。
設定例
DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", "NAME": "mydb", "USER": "postgres", "PASSWORD": "postgres", "HOST": "127.0.0.1", "TIME_ZONE": "Asia/Tokyo", "CONN_MAX_AGE": 6, } }
注意点
Django では 1 ワーカースレッドに対し 1 つの DB 接続が確立されるため、最大接続数は Django の最大ワーカースレッド数になります。DB 接続が無いスレッドは DB 接続を行ったら、CONN_MAX_AGE の秒間 DB 接続を維持し、その間に DB への別のリクエストが必要になったらスレッドはその DB 接続を使い回します。
ただし注意点として、runserver での実行時はリクエスト処理のたびに新しいスレッドを作成するため、瞬間的に DB サーバー側の最大接続数を超える可能性があります。なので開発環境ではこの設定はすべきではありません。
例えば CONN_MAX_AGE を 120 秒に設定すると、120 秒間はそのスレッドが DB 接続を維持し続けますが、そのスレッドが他のリクエストで使われることはないので無駄な消費になります。その 120 秒間に 120 リクエストあれば 120 接続が必要になりますが、PostgreSQL サーバのデフォルトの最大接続数は 100 なので溢れた 20 接続試行は接続エラーになってしまいます。
関連する gunicorn 設定の推奨値
Django で利用するワーカー数 (プロセス数)、各プロセスのスレッド数は gunicorn 等の WSGI アプリケーションに依存します。
gunicorn はデフォルトでワーカー数 (プロセス数) 1、プロセスあたりのスレッド数 1 です。
ワーカー数、スレッド数を増やすためには、プロセス起動時に引数として --workers 8 --threads 8 のように設定します。
gunicorn --workers 8 --threads 8 myproject.wsgi:application
ワーカースレッド数は (CPU コア数の 2 倍 + 1) が初期値としては推奨です。
なので 4 core の場合はワーカースレッド数は 9 が推奨なので、例えばプロセス数 3、スレッド数 3 が良さそうです。
コメント