接続プールは、アプリのパフォーマンスを向上させ、PostgreSQLサーバーの負荷を軽減するためのシンプルで効果的な方法です。 PgBouncerを使用してPostgreSQL接続をプールする方法の詳細については、以下をお読みください。
PostgreSQLにはかなり重い接続処理アーキテクチャがあります。着信接続ごとに、 postmaster (メインのPostgresデーモン)新しいプロセス(通常はバックエンドと呼ばれます)をフォークします )それを処理します。この設計は安定性と分離性を向上させますが、短命の接続を処理するのに特に効率的ではありません。新しいPostgresクライアント接続には、TCPのセットアップ、プロセスの作成、バックエンドの初期化が含まれます。これらはすべて、時間とシステムリソースの点でコストがかかります。
もちろん、これは、接続が頻繁に作成され、再利用せずに破棄された場合にのみ問題になります。残念ながら、ページの読み込みごとに1回データベースに接続する必要がある、PHPまたはその他の言語で記述されたアプリケーションを実行するWebノードのクラスターがあることは珍しくありません。大量の接続をすばやく連続して行うバッチジョブも一般的です。 接続プーリングの採用 このようなシナリオでは、PostgreSQLサーバーの負荷を大幅に削減し、クエリの待機時間を大幅に改善できます。
接続プールを使用すると、クライアントは、実際のPostgreSQLサーバーへの一連の直接接続を維持するプロキシサーバーに接続します。通常、クライアントは、実際のサーバーではなくプロキシサーバーに接続されていることに気づきません(また、そうすべきではありません)。プロキシはクライアントと同じノード(たとえば、各Webノード)で実行できます。その場合、クライアントは、接続オーバーヘッドが非常に低いUnixドメインソケットを介してプロキシに接続できます。プロキシが別のノードにあり、クライアントがプロキシに到達するためにTCP接続が必要な場合でも、新しいPostgresバックエンドのオーバーヘッドを回避できます。
PgBouncerとは何ですか?
PgBouncerは、PostgreSQL用のオープンソースで軽量なシングルバイナリ接続プールです。 1つ以上のデータベース(場合によっては異なるサーバー上)への接続をプールし、TCPおよびUnixドメインソケットを介してクライアントにサービスを提供できます。
PgBouncerは、一意のユーザー、データベースペアごとに接続のプールを維持します。通常、これらの接続の1つを新しい着信クライアント接続に渡し、クライアントが切断したときにプールに戻すように構成されています。 PgBouncerをより積極的にプールするように構成できるため、接続境界ではなく、トランザクションまたはステートメント境界で接続を取得してプールに戻すことができます。ただし、これらには望ましくない結果が生じる可能性があります。
ディストリビューションのパッケージマネージャーを使用してPgBouncerをインストールできるはずです:
# RedHat/CentOS/..
$ sudo yum install pgbouncer
# Debian/Ubuntu/..
$ sudo apt-get install pgbouncer
また、標準のPostgres APTおよびYUMリポジトリからも入手できます。これは、ディストリビューションのパッケージが古いか壊れている場合に使用できます。
PgBouncerはメインの構成ファイルに依存しており、通常は/etc/pgbouncer/pgbouncer.ini
として保存されます。 。 pgbouncerをsystemdサービスとして呼び出すことも、この構成ファイルへのパスを使用してスーパーユーザー権限がなくても単に実行することもできます。
試してみるために、サーバー上にデータベースdb1とユーザーuser1を作成しましょう:
$ sudo -u postgres psql
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
postgres=# create user user1 password 'user1pass';
CREATE ROLE
postgres=# create database db1 owner user1;
CREATE DATABASE
postgres=#
クライアントはデータベースdb1
に接続します ユーザー名user1
andpassword user1pass
。私たちの目標は、クライアントをPgBouncerに接続させ、実際のサーバーへの接続をプロキシしてプールすることです。
それでは、次の内容のファイルを(どこにでも)作成しましょう:
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
また、同じディレクトリに「userlist.txt」ファイルを作成し、PgBouncerが接続を許可するユーザーのユーザー名と(ハッシュされた)パスワードを使用する必要があります。次の内容で「userlist.txt」を作成します。
"user1" "md5638b81c77071ea624d1ad4adb1433540"
2番目の値は、「user1passuser1」のMD5で、接頭辞として「md5」が付いています。これは通常のPostgresの規則です。
それでは、フォアグラウンドでPgBouncerを起動しましょう:
$ /usr/sbin/pgbouncer pgbouncer.ini
2019-02-05 11:46:18.011 10033 LOG file descriptor limit: 1024 (H:1048576), max_client_conn: 100, max fds possible: 130
2019-02-05 11:46:18.012 10033 LOG listening on 127.0.0.1:16432
2019-02-05 11:46:18.013 10033 LOG listening on unix:/tmp/.s.PGSQL.16432
2019-02-05 11:46:18.014 10033 LOG process up: pgbouncer 1.9.0, libevent 2.0.21-stable (epoll), adns: c-ares 1.12.0, tls: OpenSSL 1.1.0j 20 Nov 2018
これで、127.0.0.1TCPポート16432とUnixドメインソケット/tmp/.s.PGSQL.16432
でリッスンするPgBouncerを起動しました。 。このプロキシサーバーで使用できる唯一の「データベース」はdb1
です。 。このサーバーに接続できる唯一のユーザーはuser1
です 。 psql
に接続してみましょう :
$ psql -U user1 -p 16432 -h localhost db1
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
db1=> select inet_server_addr(), inet_server_port();
inet_server_addr | inet_server_port
------------------+------------------
127.0.0.1 | 5432
(1 row)
db1=>
クライアント(psql)はlocalhost:16432に正常に接続しますが、接続が実際にlocalhost:5432にプロキシされていることがわかります。
切断して再度接続を数回試してから、実際のサーバーにまだ接続がいくつあるかを確認してください。
postgres=# select count(*) from pg_stat_activity
postgres-# where datname='db1' and usename='user1';
count
-------
1
(1 row)
クライアントが切断しても、PgBouncerは実際の接続を切断しません。PgBouncerが構成ファイル内のプールごとに維持する最小、最大、および予約済みの接続を構成できます。
PgBouncerのデプロイ
PgBouncerをどこにインストールして実行しますか?さまざまな答えがあり、さまざまな利点があります:
- Postgresサーバーノード上 :同じノードに、PostgreSQLサーバー自体と一緒にインストールできます。クライアントは、PostgresポートではなくPgBouncerポートに接続します。これには、内部で接続プールを実行する「拡張」Postgresの効果があります。また、PgBouncerの構成ファイルのコピーを1つだけ維持する必要があります。一方、これには、PostgreSQLサーバーノードでも実際に何か他のものを実行することが含まれます。これは、簡単ではないか、許可されていない(ファイアウォール、ポリシー)、または不可能である可能性があります(AWSRDS)。
- クライアントノード上 :各クライアントノードにPgBouncerをインストールできます。たとえば、各WebノードはApacheとPHPを実行し、PHPスクリプトはlocalPgBouncerに接続します。これには、サーバーのセットアップを妨げる必要がないという利点があり、プール構成を使用してサーバーの負荷を予測可能に保つことができます。反対に、クライアントノードの数が膨大な場合、または負荷に応じて大幅に変化する可能性があります。トラフィックが多いと、サーバーがすぐに過負荷になる可能性があります。
- スタンドアロンクラスターとして :HAProxyなどのTCPロードバランサーが前面にある、独立したステートレスPgBouncerノードのクラスターを持つ3番目のオプション。このセットアップは、他の2つのオプションよりも複雑ですが、最大限の制御と構成可能性を提供します。
PgBouncerを使用すると、管理者としてマークされたユーザーは、「pgbouncer」と呼ばれる仮想データベースに接続し、コマンドを発行してサーバーを制御し、統計を表示できます。これを試すには、まずpgbouncer.iniファイルを変更して「user1」を管理者としてマークします。
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
admin_users = user1
これで、user1は「pgbouncer」という名前のデータベースに接続できます。
$ psql -U user1 -p 16432 -h localhost pgbouncer
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1), server 1.9.0/bouncer)
Type "help" for help.
pgbouncer=#
ここから、特定のデータベースの有効化または無効化、構成の検査と再読み込みなど、さまざまなことを実行できます。
pgbouncer=# RELOAD;
RELOAD
pgbouncer=# DISABLE db1;
DISABLE
pgbouncer=# ENABLE db1;
ENABLE
pgbouncer=# SHOW FDS;
fd | task | user | database | addr | port | cancel | link | client_encoding | std_strings | datestyle | timezone | pa
----+--------+-------+----------+-----------+-------+----------------+------+-----------------+-------------+-----------+-----------+---
6 | pooler | | | 127.0.0.1 | 16432 | 0 | 0 | | | | |
7 | pooler | | | unix | 16432 | 0 | 0 | | | | |
9 | server | user1 | db1 | 127.0.0.1 | 5432 | 45404395804679 | 0 | UTF8 | on | ISO, MDY | localtime |
(3 rows)
次のような、PgBouncerに関するさまざまな統計を表示するコマンドもあります。
- クエリ期間、クライアント待機時間、ネットワーク使用量、トランザクション数に関するデータベースごとの統計
- アクティブなクライアントと待機中のクライアント、アイドル状態のサーバー接続と使用済みサーバー接続の数に関するプールごとの統計
統計は、「SHOW xyz」スタイルのコマンドを使用して取得されます。たとえば、次のようにプール関連の統計をフェッチします。
pgbouncer=# SHOW POOLS;
-[ RECORD 1 ]---------
database | db1
user | user1
cl_active | 0
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 1
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | session
-[ RECORD 2 ]---------
database | pgbouncer
user | pgbouncer
cl_active | 1
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 0
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | statement
PgBouncerホームページには、PgBouncerのさまざまな機能と構成オプションすべてに関する詳細があります。
- PgBouncerホームページ
- PgBouncerGitHubリポジトリ
- PostgresWikiには接続プールに関する情報があります
- Pgpoolは接続プールのもう1つのオプションです