Pgpoolは、実稼働PostgreSQLセットアップのデフォルト部分であった10年前よりも、今日では実際的ではありません。多くの場合、誰かがPostgreSQLクラスターについて話していたとき、彼らはPostgreSQLインスタンス自体ではなくpgpoolの背後にあるpostgreSQLを参照していました(これは正しい用語です)。 Pgpoolは、最も影響力のあるPostgresプレーヤー間で認識されます:postgresqlコミュニティ、commandprompt、2ndquadrant、EDB、citusdata、postgrespro(年齢順に並べられ、影響はありません)。リンクの認識レベルが大きく異なることに気づきました。postgresの世界におけるpgpoolの全体的な影響を強調したいと思います。現在最もよく知られているpostgresの「ベンダー」のいくつかは、pgpoolがすでに有名になった後に見つかりました。では、何がそんなに有名なのですか?
最も需要の高い提供機能のリストだけで見栄えが良くなります:
- ネイティブレプリケーション
- 接続プール
- 読み取りスケーラビリティのための負荷分散
- 高可用性(仮想IP、オンラインリカバリ、フェイルオーバーを備えたウォッチドッグ)
さて、サンドボックスを作って遊んでみましょう。私のサンプルセットアップはマスタースレーブモードです。通常、負荷分散と一緒にストリーミングレプリケーションを使用するため、これが今日最も人気があると思います。最近、レプリケーションモードはほとんど使用されていません。ほとんどのDBAは、ストリーミングレプリケーションとpglogicalを優先してスキップし、以前はslonyを使用していました。
レプリケーションモードには、多くの興味深い設定と確かに興味深い機能があります。ただし、ほとんどのDBAは、pgpoolに到達するまでにマスター/マルチスレーブがセットアップされています。そのため、彼らは自動フェイルオーバーとロードバランサーを探しており、pgpoolは既存のマスター/マルチスレーブ環境にすぐに使用できるように提供しています。言うまでもなく、Postgres 9.4以降、ストリーミングレプリケーションは大きなバグなしで機能し、10個のハッシュインデックスからレプリケーションがサポートされているため、使用を妨げるものはほとんどありません。また、ストリーミングレプリケーションはデフォルトで非同期です(同期に構成可能で、「線形」同期ではない複雑なセットアップですが、ネイティブpgpoolレプリケーションは同期(つまり、データ変更が遅い)であり、選択オプションはありません。追加の制限も適用されます。Pgpoolマニュアル自体は可能な場合は、pgpoolネイティブを介したストリーミングレプリケーション)。そして、これが私の選択です。
ああ、でも最初にインストールする必要があります-そうですか?
インストール(ubuntuの上位バージョン)
まず、lsb_release-aを使用してubuntuのバージョンを確認します。私にとってレポは:
[email protected]:~# sudo add-apt-repository 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
> sudo apt-key add -
OK
[email protected]:~# sudo apt-get update
最後にインストール自体:
sudo apt-get install pgpool2=3.7.2-1.pgdg16.04+1
構成:
推奨モードからデフォルト設定を使用します:
zcat /usr/share/doc/pgpool2/examples/pgpool.conf.sample-stream.gz > /etc/pgpool2/pgpool.conf
開始:
設定を見逃した場合は、次のように表示されます:
2018-03-22 13:52:53.284 GMT [13866] FATAL: role "nobody" does not exist
ああ本当です-私の悪いですが、簡単に修正できます(すべてのヘルスチェックと回復に同じユーザーが必要な場合は、1つのライナーで盲目的に実行できます):
[email protected]:~# sed -i s/'nobody'/'pgpool'/g /etc/pgpool2/pgpool.conf
先に進む前に、すべてのクラスターでデータベースpgpoolとユーザーpgpoolを作成しましょう(私のサンドボックスでは、これらはマスター、フェイルオーバー、スレーブであるため、マスターでのみ実行する必要があります):
t=# create database pgpool;
CREATE DATABASE
t=# create user pgpool;
CREATE ROLE
ついに-開始:
[email protected]:~$ /usr/sbin/service pgpool2 start
[email protected]:~$ /usr/sbin/service pgpool2 status
pgpool2.service - pgpool-II
Loaded: loaded (/lib/systemd/system/pgpool2.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2018-04-09 10:25:16 IST; 4h 14min ago
Docs: man:pgpool(8)
Process: 19231 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 8770 (pgpool)
Tasks: 10
Memory: 5.5M
CPU: 18.250s
CGroup: /system.slice/pgpool2.service
├─ 7658 pgpool: wait for connection reques
├─ 7659 pgpool: wait for connection reques
├─ 7660 pgpool: wait for connection reques
├─ 8770 /usr/sbin/pgpool -n
├─ 8887 pgpool: PCP: wait for connection reques
├─ 8889 pgpool: health check process(0
├─ 8890 pgpool: health check process(1
├─ 8891 pgpool: health check process(2
├─19915 pgpool: postgres t ::1(58766) idl
└─23730 pgpool: worker proces
すばらしい-最初の機能に進むことができるように-負荷分散を確認しましょう。使用する必要のある要件がいくつかあり、ヒントをサポートし(たとえば、同じセッションでバランスを取るため)、白黒リストされた関数があり、正規表現ベースのリダイレクト設定リストがあります。洗練されています。残念ながら、そのすべての機能を徹底的に調べることはこのブログの範囲外になるため、最も単純なデモを確認します。
まず、非常に単純なもので、選択に使用されるノードが示されます(私のセットアップでは、別のクラスターが実行されていて干渉したくないため、マスターは5400でスピンし、スレーブは5402で、フェイルオーバーは5401で、pgpool自体は5433です。それで):
[email protected]:~$ psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1"
current_setting
-----------------
5400
(1 row)
次にループ内:
[email protected]:~$ (for i in $(seq 1 99); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
9 5400
30 5401
60 5402
素晴らしい。ノード間の負荷は確実にバランスしますが、均等にバランスが取れていないようです。おそらく、各ステートメントの重みを知っているほど賢いのでしょうか。期待される結果で分布を確認しましょう:
t=# show pool_nodes;
node_id | hostname | port | status | lb_weight | role | select_cnt | load_balance_node | replication_delay
---------+-----------+------+--------+-----------+---------+------------+-------------------+-------------------
0 | localhost | 5400 | up | 0.125000 | primary | 122 | false | 0
1 | localhost | 5401 | up | 0.312500 | standby | 169 | false | 0
2 | localhost | 5402 | up | 0.562500 | standby | 299 | true | 0
(3 rows)
いいえ-pgpoolはステートメントの重みを分析しません-それは再び彼女の設定を持つDBAでした!設定(lb_weight属性を参照)は、実際のクエリ宛先ターゲットと調整します。対応する設定を変更することで、(ここで行ったように)簡単に変更できます。例:
[email protected]:~$ grep weight /etc/pgpool2/pgpool.conf
backend_weight0 =0.2
backend_weight1 = 0.5
backend_weight2 = 0.9
[email protected]:~# sed -i s/'backend_weight2 = 0.9'/'backend_weight2 = 0.2'/ /etc/pgpool2/pgpool.conf
[email protected]:~# grep backend_weight2 /etc/pgpool2/pgpool.conf
backend_weight2 = 0.2
[email protected]:~# pgpool reload
[email protected]:~$ (for i in $(seq 1 9); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
6 5401
3 5402
今日のホワイトペーパーをダウンロードするClusterControlを使用したPostgreSQLの管理と自動化PostgreSQLの導入、監視、管理、スケーリングを行うために知っておくべきことについて学ぶホワイトペーパーをダウンロードする 素晴らしい!提供される次の優れた機能は、接続プールです。 3.5では、accept()呼び出しをシリアル化することで「雷の群れの問題」が解決され、「クライアント接続」時間が大幅に短縮されます。それでも、この機能は非常に簡単です。複数のレベルのプーリングや同じデータベース用に構成された複数のプール(pgpoolでは、負荷分散のdatabase_redirect_preference_listを使用してselectを実行する場所を選択できます)、またはpgBouncerが提供するその他の柔軟な機能は提供されません。
短いデモ:
t=# select pid,usename,backend_type, state, left(query,33) from pg_stat_activity where usename='vao' and pid <> pg_backend_pid();
pid | usename | backend_type | state | left
------+---------+----------------+-------+--------------
8911 | vao | client backend | idle | DISCARD ALL
8901 | vao | client backend | idle | DISCARD ALL
7828 | vao | client backend | idle | DISCARD ALL
8966 | vao | client backend | idle | DISCARD ALL
(4 rows)
Hm - did I set up this little number of children?
t=# pgpool show num_init_children;
num_init_children
-------------------
4
(1 row)
ああ、本当です。デフォルトの32より低く変更したので、出力に数ページかかることはありません。それでは、セッション数を超えてみましょう(以下では、postgresセッションを非同期でループで開くため、6つのセッションがほぼ同時に要求されます):
[email protected]:~$ for i in $(seq 1 6); do (psql -h localhost -p 5433 t -U vao -c "select pg_backend_pid(), pg_sleep(1), current_setting('port'), clock_timestamp()" &); done
[email protected]:~$ pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
8904 | | 5402 | 2018-04-10 12:46:55.626206+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
9391 | | 5401 | 2018-04-10 12:46:55.630175+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+------------------------------
8911 | | 5400 | 2018-04-10 12:46:55.64933+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
8904 | | 5402 | 2018-04-10 12:46:56.629555+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
9392 | | 5402 | 2018-04-10 12:46:56.633092+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+------------------------------
8910 | | 5402 | 2018-04-10 12:46:56.65543+01
(1 row)
これにより、セッションは3つになります。1つは上記のセッション(pg_stat_activityから選択)によって取得されるため、4-1=3になります。 pg_sleepが1秒間の仮眠を終了し、postgresによってセッションが閉じられるとすぐに、次のセッションが開始されます。最初の3つが終了した後、次の3つのステップが開始されます。残りはどうなりますか?それらは、次の接続スロットが解放されるまでキューに入れられます。次に、serialize_acceptの次に説明するプロセスが実行され、クライアントが接続されます。
は?セッションモードでのセッションプーリングだけですか?すべてですか?..いいえ、ここでキャッシュ手順を実行します。見てください。:
postgres=# /*NO LOAD BALANCE*/ select 1;
?column?
----------
1
(1 row)
pg_stat_activityの確認:
postgres=# select pid, datname, state, left(query,33),state_change::time(0), now()::time(0) from pg_stat_activity where usename='vao' and query not like '%DISCARD%';
pid | datname | state | left | state_change | now
-------+----------+-------+-----------------------------------+--------------+----------
15506 | postgres | idle | /*NO LOAD BALANCE*/ select 1, now | 13:35:44 | 13:37:19
(1 row)
次に、最初のステートメントを再度実行し、state_changeが変更されていないことを確認します。これは、既知の結果を得るためにデータベースにアクセスすることすらできないことを意味します。もちろん、可変関数を配置すると、結果はキャッシュされません。試してみてください:
postgres=# /*NO LOAD BALANCE*/ select 1, now();
?column? | now
----------+------------------------------
1 | 2018-04-10 13:35:44.41823+01
(1 row)
結果と同様にstate_changeが変化することがわかります。
ここでの最後のポイント-なぜ/*負荷バランスなし*/?..マスターでpg_stat_activityをチェックし、マスターでもクエリを実行することを確認します。同じように、/ * NO QUERY CACHE * /ヒントを使用して、キャッシュされた結果が得られないようにすることができます。
短いレビューはもうたくさんありますか?しかし、HAの部分にも触れませんでした!そして、多くのユーザーは特にこの機能のためにpgpoolに目を向けています。さて、これは話の終わりではありません、これはパート1の終わりです。パート2が近づいています。ここでは、HAとpgpoolの使用に関するその他のヒントについて簡単に説明します...