PostgreSQLで非同期レプリケーションを設定する

「SAVACAN」担当のMKです。

今回のブログではデータベースの高可用性を実現するための重要な技術であるPostgreSQLのレプリケーションについてご紹介致します。

PostgreSQLを稼働機と予備機で運用しており、レプリケーションを行わない場合、下記の様な重要な課題が発生します。
・予備機へ切り替える際、バックアップデータからの復元作業が必要
・前回バックアップ時のデータに巻き戻りが発生
・復旧作業に時間を要し、ダウンタイムが長引く

この課題を解消する技術がレプリケーションになります。レプリケーションを活用することで、ほぼリアルタイムでデータの同期が行われ、障害発生時の迅速な復旧が可能となります。

まず初めにレプリケーションの概要からご説明し、最後に具体的な設定手順や動作確認方法についてご紹介をさせて頂きます。

目次

PostgreSQLのレプリケーションとは

今回のブログでは、PostgreSQLにおけるレプリケーションの設定方法にフォーカスして解説します。そのため、レプリケーションの概要については簡単に紹介いたします。

PostgreSQLでは、プライマリDBで生成されたトランザクションログ(WAL: Write Ahead Log)を元にセカンダリサーバーへのデータ同期を実現しています。
セカンダリサーバーは読み取り専用として機能し、書き込みは行えませんが、参照系の負荷を分散する際に有効です。ただし、PostgreSQL本体には負荷分散機能はまでは備わっていません。そのため、Pgpool-IIなどの外部ツールを組み合わせることで、クエリの負荷分散や接続管理を実現することが可能です。

PostgreSQLのレプリケーションの種類

こちらも今回のブログでは、概要の説明のみとさせて頂きます。

スクロールできます
ver.レプリケーション機能
9.0非同期レプリケーションセカンダリのWALにデータを書き込む前にユーザーに応答を返します。
セカンダリの応答を待たないため速度遅延がありません。
9.1同期レプリケーションセカンダリのWALにデータを書き込んでからユーザーに応答を返します。
非同期に比べ速度の遅延がありますが、より確実なデータ同期が行われます。

設定により、 セカンダリのメモリへの書き込みまでで同期完了とする事も可能です。
9.2カスケードレプリケーション3台以上の構成でレプリケーションを行う際、WALを受け取ったセカンダリが別のセカンダリへWALを転送する事で、プライマリの負荷を軽減します。管理コストが上がる可能性があります。
10ロジカルレプリケーション
(論理レプリケーション)
バージョン9.Xで導入されたレプリケーションはストリーミングレプリケーションと言い、データベース全体を同期させます。
ロジカルレプリケーションでは、データベース単位・テーブル単位など柔軟に同期設定ができます。

ただし、DDLは同期されない、対応オブジェクトに制限がある、など制約があるため、負荷分散やバックアップなどの用途には向かないとされています。

今回の動作確認環境

PostgreSQLバージョン:9.6

サーバーIPアドレス
プライマリ(db1):192.168.8.101
セカンダリ(db2):192.168.8.102

設定前の確認

PostgreSQLのインストール前に、以下の注意事項を事前にご確認いただく必要があります。
最新の手順は方々で開設されておりますので、今回はバージョン8.X系の時代に行われていた疑似レプリケーションの懐かしい手順を紹介します。
現在はssh接続やwal等の手動転送は必要ありません。

  • プライマリの/var/lib/pgql/walarchフォルダにWALを書き込みsshで同期します。
  • 事前にpostgresユーザーで認証なしでssh接続できるように設定しておく必要があります。
  • セカンダリ側でのinitdbは実行しません。(セカンダリ側でinitdbを実行するとDBの整合性が取れないためレプリケーションでのデータ取得ができません)
  • セカンダリ側でinitdbを実行してしまったらインストールからやり直します。

また、今回紹介する手順の前提としてsshの認証なしでの接続手順、PostgreSQLのインストール、チューニングは含んでおりません。

プライマリ側の設定内容

設定内容はSSHでセカンダリに転送しますのでプライマリ側で設定します。
まずWALを設定します。

vi /var/lib/pgsql/data/postgresql.conf

wal_level = replica
archive_mode = on        # onでWALのログをアーカイブしarchive_commandで指定した場所に保存
archive_command = 'cp %p /var/lib/pgsql/walarch/%f'
max_wal_senders = 1      # WAL送信者接続数(今回はセカンダリが1台なので1としている)
archive_timeout = 60

WALの保存ディレクトリを作成します。

mkdir /var/lib/pgsql/walarch/
chmod -R 777 /var/lib/pgsql/walarch/

接続するネットワークを設定します。

vi /var/lib/pgsql/data/pg_hba.conf

host all all 192.168.8.0/24 trust				# 191.168.8.0からの問い合わせを許可
host replication postgres 192.168.8.102/24 trust	# 192.168.8.102からpostgresユーザーでのレプリケーション接続を許可

以上でレプリケーションに関する設定が完了です。postgresを起動します。

systemctl start postgresql

セカンダリに転送するバックアップを作成します。 バックアップを始める時点でのバックアップの開始位置として記録します。

psql -c "select pg_start_backup('20250523')"
 pg_start_backup
-----------------
 0/2000020

バックアップファイルを作成します。

tar cfvz /var/lib/pgsql/data.tar.gz /var/lib/pgsql/data/
tar cfvz /var/lib/pgsql/walarch.tar.gz /var/lib/pgsql/walarch/

バックアップ後のWALの終了位置を記録します。

psql -c "select pg_stop_backup()"
 pg_stop_backup
----------------
 0/20000D8

バックアップファイルの確認をします。
STARTで始まるWALセグメントファイルよりも古いファイルは不要なため削除しても問題ありません。

cat /var/lib/pgsql/walarch/*.backup

START WAL LOCATION: 0/3000020 (file 000000010000000000000003)
STOP WAL LOCATION: 0/3000920 (file 000000010000000000000003)
CHECKPOINT LOCATION: 0/3000058
START TIME: 2016-06-02 15:36:35 JST
LABEL: allok
STOP TIME: 2016-06-02 15:38:33 JST

postgresユーザーでセカンダリ側に転送をします。

scp data.tar.gz postgres@192.168.8.102:/var/lib/pgspl
scp walarch.tar.gz postgres@192.168.8.102:/var/lib/pgspl

セカンダリ側の設定内容

プライマリから転送したファイルを/var/lib/pgsqlの下で解凍します。

tar zxvf data.tar.gz
tar zxvf walarch.tar.gz

プライマリから転送したpostmaster.pidファイル(プロセスIDを記録したファイル)を削除します。

rm /var/lib/pgsql/data/postmaster.pid

スタンバイ側であることを設定します。

vi /var/lib/pgsql/data/postgresql.conf

hot_standby = on

以下はプライマリのみに必要な記述ですので削除します。

vi /var/lib/pgsql/data/pg_hba.conf

host replication postgres 192.168.8.102/24 trust
→削除かコメントアウトしておきます

レプリケーションの設定ファイルを作成します。

vi /var/lib/pgsql/data/recovery.conf

standby_mode = 'on'
primary_conninfo = 'host=192.168.8.101 port=5432 user=postgres'
restore_command = 'scp 192.168.8.101:/var/lib/pgsql/walarch/%f %p'
trigger_file = '/var/lib/pgsql/data/rep_end'
archive_cleanup_command = '/usr/local/pgsql/bin/pg_archivecleanup /var/lib/pgsql/walarch %r'

trigger_fileはセカンダリ側でプライマリからのレプリケーションを終了する際に手動で作成するファイルです。
セカンダリ側で以下のファイルを作成すると、セカンダリ側での更新(update、insert、delete)を開始します。

touch /var/lib/pgsql/data/rep_end

作成された /var/lib/pgsql/data/rep_end ファイルは自動的に削除され、リカバリが完了すると recovery.conf は recovery.done にファイル名が変更されます。

セカンダリサーバーをプライマリサーバーに昇格させると、再びセカンダリサーバーに戻すことはできません。同様に、プライマリサーバーも元のプライマリサーバーには戻れませんので、フェイルオーバーを判断するタイミングには十分にご注意ください。

もしトラブルがすぐに解消できるものであれば、プライマリサーバーの復旧を行い、復旧に〇時間以上かかる見込みの場合には、フェイルオーバーを実施するなど、運用基準を設けることをおすすめします。

以上でセカンダリ側の設定も完了となります。

起動時の動作確認ポイント

プライマリ側で以下のログが出力されていることを確認します。
出力されるログファイルはpostgresql.confの設定(log_destination)によります。

replication connection authorized: user=postgres host=192.168.8.102 port=52033

セカンダリ側で以下のログが出力されていることを確認します。

streaming replication successfully connected to primary

セカンダリ側で書き込みができないことを確認します。

[postgres@db2 ~]$ createdb -E UTF8 testdb
createdb: database creation failed: ERROR:  cannot execute CREATE DATABASE in a read-only transaction

セカンダリ側で参照ができることを確認します。

[postgres@db2~]$ psql -d test -c "select * from test_table"
  count  
---------
 3219407
(1 行)

[postgres@db2 ~]$ 

レプリケーション進捗状況確認

セカンダリ側で現在のWALのレコード位置を取得します。

[postgres@db2 ~]$ ps aux|grep postgres|grep wal
postgres 39894  0.0  0.0 17560544 2328 ?       Ss    5月23   12:30 postgres: wal receiver process   streaming 192E/D6011AA0

WALのレコード位置:192E/D6011AA0
192E/D6011AA0はWALのレコード位置でxlogid(WAL ファイルの識別子)/xrecoff(WAL ファイル内でのレコードのオフセット)の形式で16進数の値が表示されます。

プライマリ側で現在のWALのレコード位置を取得します。
セカンダリ側で取得してから時間がたった場合はセカンダリ側での取得からやり直します。

[postgres@db1 ~]$ ps aux|grep postgres|grep wal
postgres 22428  0.0  0.0 17581812 3656 ?       Ss    5月23   12:30 postgres: wal sender process postgres 192.168.8.102(36138) streaming 192E/D6068FB8

WALのレコード位置はプライマリ側から取得すると、システムの更新頻度によってはセカンダリ側の方が進んでいるという結果になりますのでセカンダリ側から取得すると確実です。

計算方法について
16進数を10進数に変換することで遅延している書き込みの状況を把握することができます。

・セカンダリ側
16進数:192E/D6011AA0
10進数:6446/3590396576

・プライマリ側
16進数:192E/D6068FB8
10進数:6446/3590754232

これまでの確認を経て、運用を開始する準備が整いました。
データ同期をしないアクティブ・スタンバイ構成に比べて注意が必要です。サーバーの状況を常に監視し、安定した運用を心がけてください。

最後に

space-iでは、PostgreSQLを活用した大規模システムの運用実績が豊富にあります。
システム運用や構築に関するお悩みがあれば、お客様のご利用状況やサーバー構成に応じた最適な提案をさせていただきます。お気軽にお問い合わせください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次