PostgreSQLはストリーミングレプリケーションと呼ばれるデータコピーの仕組みがあります。レプリケーションの構成によっては、マスターサーバの更新がスタンバイサーバに反映されるのを待ってからCOMMITを返すホットスタンバイの構成を採用する事もできます。しかし、ホットスタンバイの構成は、スタンバイサーバへの参照系クエリとWALの適用がコンフリクト(競合)し待ち状態になる事もあります。
このページではコンフリクトの発生原因とその緩和方法についてまとめます。
- PostgreSQL インストール
- PostgreSQL データベースの作成
- PostgreSQL contribモジュールの使い方
- PostgreSQL パラメタの設定方法
- PostgreSQL ベンチマークツールの紹介
- PostgreSQL WAL(Write Ahead Log)の基本説明
- PostgreSQL バックアップとリストア
- PostgreSQL PITR(Point In Time Recovery)基本概念の説明
- PostgreSQL PITR(Point In Time Recovery)操作方法の説明
- PostgreSQL PITR(Point In Time Recovery)タイムライン操作
- PostgreSQL ストリーミングレプリケーションの最小構成
- PostgreSQL ストリーミングレプリケーションのパラメタ説明
- PostgreSQL ストリーミングレプリケーションの障害復旧
- PostgreSQL ストリーミングレプリケーションの多段構成
- PostgreSQL ストリーミングレプリケーションのDR向け設定
- PostgreSQL ストリーミングレプリケーションのコンフリクト (いまここ)
- PostgreSQL 自動バキューム(AUTO VACUUM)
- PostgreSQL HOT(Heap Only Tuple)
- PostgreSQL インデックスのメンテナンス
- PostgreSQL 統計情報の更新
- PostgreSQL 実行計画
- PostgreSQL スロークエリの調査方法
動作確認構成
以下の環境で動作確認を行います。
+------------------+ +------------------+ | 192.168.56.10/24 | | 192.168.56.11/24 | | centos10 |---->| centos11 | | (primary) | | (secondary) | +------------------+ +------------------+
事前準備
マスターサーバの構築
postgresql.confおよびpg_hba.confに以下を加筆します。
スタンバイサーバへのWAL適用時のコンフリクト(競合)を観察したいので、synchronous_commitはremote_applyにします。
cat << EOF >> /var/lib/pgsql/13/data/postgresql.conf listen_addresses = '0.0.0.0' max_wal_senders = 10 synchronous_commit = 'remote_apply' synchronous_standby_names = 'centos11' EOF cat << EOF >> /var/lib/pgsql/13/data/pg_hba.conf host replication postgres 192.168.56.0/24 trust EOF
再起動し設定を反映させます。
systemctl restart postgresql-13.service
スタンバイサーバの構築
pg_basebackupコマンドを使用して、プライマリサーバのデータを1台目スタンバイサーバへコピーします。
pg_basebackup -R -D ${PGDATA} -h 192.168.56.10
postgresql.auto.confのsynchronous_standby_namesにapplication_nameを加筆します。
# vi /var/lib/pgsql/13/data/postgresql.auto.conf primary_conninfo = 'user=postgres <omitted> application_name=centos11'
マスターサーバとしての設定をコメントアウトします。
# vi /var/lib/pgsql/13/data/postgresql.conf #listen_addresses = '0.0.0.0' #max_wal_senders = 10 #synchronous_commit = 'remote_apply' #synchronous_standby_names = 'centos11'
postgresqlを起動します。
systemctl start postgresql-13.service
コンフリクトの実験
コンフリクトが発生しやすい状況の作成
マスターサーバへの排他ロックが必要な更新処理とスタンバイサーバへの参照クエリはコンフリクトします。例えば、マスターサーバへのDROP TABLEは排他ロックを取得するので、スタンバイサーバへの参照クエリ実行中はDROP TABLEを実行する事ができません。このような状況が発生すると、デフォルト設定の場合は最大で30秒の待ちが発生します。
コンフリクトを観察できるよう30秒以上かかるクエリを作ってみましょう。まずはマスターサーバにpgbenchコマンドを使って、5クライアント10,000トランザクションを更新処理を発生させます。すると、pgbench_historyテーブルに50,000レコードのデータが作成されます。
createdb test /usr/pgsql-13/bin/pgbench -i test /usr/pgsql-13/bin/pgbench -c 5 -t 10000 test
pgbench_historyテーブルの直積を求めるクエリを実行します。このクエリが30秒以上かかる事を確認します。
psql test -c "SELECT count(*) FROM pgbench_history t1, pgbench_history t2;"
コンフリクトの再現
スタンバイサーバにて30秒以上の時間がかかるクエリを実行します。
psql test -c "SELECT count(*) FROM pgbench_history t1, pgbench_history t2;"
スタンバイサーバの実行中に、プライマリサーバにてDROP TABLEを発行します。
psql test -c "DROP TABLE pgbench_history;"
30秒経過するとスタンバイ側のクエリがキャンセルされ、プライマリ側のDROP DATABASEが実行されます。30秒経過すると、スタンバイサーバとプライマリサーバで以下のような標準出力が得られます。
[postgres@centos10 ~]$ psql test -c "DROP TABLE pgbench_history;" DROP TABLE [postgres@centos10 ~]$
[postgres@centos11 ~]$ psql test -c "select count(*) from pgbench_history t1, pgbench_history t2;" ERROR: リカバリで競合が発生したためステートメントをキャンセルしています DETAIL: ユーザリレーションのロックを長く保持し過ぎていました [postgres@centos11 ~]$
スタンバイサーバでpg_stat_database_conflictsテーブルを参照すると、コンフリクト(競合)が発生した回数を観察する事ができます。
testデータベースのconfl_lockがカウントアップされているのが分かります。
[postgres@centos11 ~]$ psql -c "select * from pg_stat_database_conflicts;" datid | datname | confl_tablespace | confl_lock | confl_snapshot | confl_bufferpin | confl_deadlock -------+-----------+------------------+------------+----------------+-----------------+---------------- 14384 | postgres | 0 | 0 | 0 | 0 | 0 1 | template1 | 0 | 0 | 0 | 0 | 0 14383 | template0 | 0 | 0 | 0 | 0 | 0 16557 | test | 0 | 1 | 0 | 0 | 0 (4 rows) [postgres@centos11 ~]$
コンフリクトの緩和策
コンフリクトに関するパラメタ
プライマリサーバに設定可能なパラメタは以下の通りです。
パラメタ | 意味 |
---|---|
vacuum_defer_cleanup_age | VACUUMやHOTの物理削除を延期させるトランザクション数を指定。VACUUMやHOTの物理削除がコンフリクトを頻発させる場合は緩和策となりうる。 |
スタンバイサーバに設定可能なパラメタは以下の通りです。
パラメタ | 意味 |
---|---|
max_standby_archive_delay | アーカイビングからのWALを適用する場合、スタンバイへのクエリと競合した場合にどの程度待つかを指定するパラメタ。デフォルトは30秒。-1を指定した場合は永久に待ち続ける。 |
max_standby_streaming_delay | プライマリからのWALを適用する場合、スタンバイへのクエリと競合した場合にどの程度待つかを指定するパラメタ。デフォルトは30秒。-1を指定した場合は永久に待ち続ける。 |
hot_standby_feedback | スタンバイサーバで実行している処理をプライマリサーバへフィードバックを行う。VACUUMやHOTの物理削除がコンフリクトを頻発させる場合は緩和策となりうる。デフォルトはoff |
wal_receiver_status_interval | hot_standby_feedbackをonにした場合のフィードバックを返す頻度。デフォルトは10秒間隔 |
max_standby_streaming_delay
スタンバイサーバのmax_standby_streaming_delayを3秒に設定します。
max_standby_streaming_delay = 3 EOF
再起動し設定を反映させます。
systemctl restart postgresql-13.service
先ほどと同様の競合(コンフリクト)を発生させます。max_standby_streaming_delayで指定した3秒でSELECTがキャンセルされた事が分かります。
[postgres@centos10 ~]$ psql test -c "DROP TABLE pgbench_history;" DROP TABLE [postgres@centos10 ~]$
[postgres@centos11 ~]$ psql test -c "SELECT count(*) FROM pgbench_history t1, pgbench_history t2;" ERROR: リカバリで競合が発生したためステートメントをキャンセルしています DETAIL: 削除されるべきバージョンの行をユーザ問い合わせが参照しなければならなかった可能性がありました。 [postgres@centos11 ~]$