PostgreSQL 13 WAL(Write Ahead Log)の基本説明

スポンサーリンク

PostgreSQLのWAL(Write Ahead Log)についてまとめます。WALはデータベースに対する更新操作が記載されたログで、ストリーミングレプリケーションやPITR(Point In Time Recovery)で使用されます。

WALのファイル確認

WALは更新操作が記録されるログです。WALの動作確認を行うために、何らかの更新操作を行います。

pgbenchを用いて簡単な更新操作を行う例を以下に示します。

createdb test
/usr/pgsql-13/bin/pgbench -i test
/usr/pgsql-13/bin/pgbench -c 5 -t 100 test

更新操作を行うと、pg_wal配下に連番のファイルが作成されます。これがWALです。

[postgres@centos10 ~]$ ls -l /var/lib/pgsql/13/data/pg_wal/
total 32768
-rw------- 1 postgres postgres 16777216 Dec 15 12:02 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Dec 15 12:03 000000010000000000000002
drwx------ 2 postgres postgres        6 Dec 15 12:00 archive_status
[postgres@centos10 ~]$ 

WALはバイナリファイルです。これを閲覧するには、pg_waldumpと呼ばれるツールを使用します。

pg_waldumpを使用するとLSN(Log Sequence Number)を調べる事ができます。LSNはログに対して付与される番号で、PITR(Point In Time Recovery)をする時は、どのLSNまでをリカバリするかを指定する事ができます。

[postgres@centos10 ~]$ /usr/pgsql-13/bin/pg_waldump /var/lib/pgsql/13/data/pg_wal/000000010000000000000001 
rmgr: XLOG        len (rec/tot):    114/   114, tx:          0, lsn: 0/01000028, prev 0/00000000, desc: CHECKPOINT_SHUTDOWN redo 0/1000028; tli 1; prev tli 1; fpw true; xid 0:3; oid 12000; multi 1; offset 0; oldest xid 3 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 0; shutdown
rmgr: XLOG        len (rec/tot):     30/    30, tx:          1, lsn: 0/010000A0, prev 0/01000028, desc: NEXTOID 20192
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/010000C0, prev 0/010000A0, desc: FPI , blkref #0: rel 1663/1/6117 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/01000150, prev 0/010000C0, desc: FPI , blkref #0: rel 1664/0/6115 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/010001E0, prev 0/01000150, desc: FPI , blkref #0: rel 1664/0/6114 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/01000270, prev 0/010001E0, desc: FPI , blkref #0: rel 1663/1/6113 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/01000300, prev 0/01000270, desc: FPI , blkref #0: rel 1663/1/6112 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/01000390, prev 0/01000300, desc: FPI , blkref #0: rel 1663/1/6111 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/01000420, prev 0/01000390, desc: FPI , blkref #0: rel 1663/1/6110 blk 0 FPW
rmgr: XLOG        len (rec/tot):     49/   137, tx:          1, lsn: 0/010004B0, prev 0/01000420, desc: FPI , blkref #0: rel 1663/1/3351 blk 0 FPW

WALバッファとWAL

WALは高速な書き込みを実現するために、メモリに書き込んでから非同期でディスクに書き込みます。メモリに書き込まれた領域はWALバッファと呼ばれます。

特段のチューニングがおこなれていない場合は、デフォルト設定の200ms間隔でWAL writterというプロセスがメモリ上のWALバッファをディスクに書き込みます。その他、クラッシュが起きた時にデータ不整合が起きないよう、様々なタイミングでディスクへの書き込みを行います。書き込みを行うタミングを以下に整理します。

  • wal writer 定期実行
  • COMMIT 実行時
  • CHECKPOINT 実行時
  • VACUUM 実行時
  • WALバッファ溢れ
  • 共有バッファ溢れ

WALのスイッチ

WALは16MB固定です。16MBを超えると次のWALに書き込みをするようになります。

例えば、000000010000000000000003への書き込みを続けたところ、このファイルが16MBを超過しました。その場合は、次は000000010000000000000004に書き込むようになります。

現在、どのWALへ書き込みを行なっているかはpg_current_wal_lsn()関数とselect pg_walfile_name()関数を組み合わせて調査する事ができます。

pg_current_wal_lsn()は、LSNの現在の値を返す関数です。

[postgres@centos10 ~]$ psql -c "SELECT pg_current_wal_lsn()"
 pg_current_wal_lsn 
--------------------
 0/3550818
(1 row)

pg_walfile_name()は引数にLSNを与える関数で、LSNがどのWALに所属するかのファイル名を返します。

[postgres@centos10 ~]$ psql -c "SELECT pg_walfile_name(pg_current_wal_lsn())"
     pg_walfile_name      
--------------------------
 000000010000000000000003
(1 row)

WALのスイッチは16MBを超えた時だけでなく、手動で行う事もできます。例えば、select pg_switch_wal()関数を使用するとWALをスイッチさせる事ができます。また、バックアップを取得する時のpg_start_back()関数でもスイッチが実施されます。

[postgres@centos10 ~]$ psql << EOF
> \x
> SELECT pg_walfile_name(pg_current_wal_lsn());
> select pg_switch_wal();
> SELECT pg_walfile_name(pg_current_wal_lsn());
> EOF
Expanded display is on.
-[ RECORD 1 ]---+-------------------------
pg_walfile_name | 000000010000000000000003

-[ RECORD 1 ]-+----------
pg_switch_wal | 0/355D700

-[ RECORD 1 ]---+-------------------------
pg_walfile_name | 000000010000000000000004

WAL Level

WALはどの程度詳細なログを出力するかを指定するwal_levelと呼ばれる設定があります。デフォルトではreplicaですが、ロジカルレプリケーションを行う場合はlogicalに変更し、最小限のログで充分な場合はminimalに変更する事もできます。

古いバージョンのPostgreSQLでは、wal_levelのデフォルト設定はminimalです。

wal_levelの設定をまとめると以下の通りです。(参照「19.5. Write Ahead Log」)

wal_level 挙動
minimal クラッシュや突然のシャットダウンから復旧するのに充分なログを記録する。ログを減らし高速化を図る時に使用
replica ストリーミングレプリケーションを行うのに充分なログを記録する
logical ロジカルレプリケーションを行うのに充分なログを記録する。ログの量が増える事に注意

wal_levelをminimalとした場合は、以下操作がWALに記録されなくなる事で高速化を図ります。

  • ALTER … SET TABLESPACE
  • CLUSTER
  • CREATE TABLE
  • REFRESH MATERIALIZED VIEW (without CONCURRENTLY)
  • REINDEX
  • TRUNCATE

wal_levelをlogicalとした場合は、ロジカルチェンジセットをWALから取り出すのに必要な情報が追加される。WALの量が増える事に注意。特に、多数のテーブルがREPLICA IDENTITY FULLと設定されていて、多くのUPDATEとDELETE文が実行される場合は、ログ増量の傾向が顕著になります。

アーカイビング

パラメタ解説

アーカイビングはWALを別ディレクトリにコピーする機能です。コピー先をNSFのような共有領域にしておけば、バックアップからのロールフォワードやPITR(Pint In Time Recovery)で使用する事ができます。

アーカイビングに必要なパラメタを以下にまとめます。

パラメタ 説明
archive_mode アーカイビングを有効にするか否かの設定。wal_levelがminimalの場合は有効化できない事に注意。
archive_command アーカイブ先を指定するコマンド。「cp -p %p /nfs/%f」のようにコピーを行うコマンドを指定します。%p, %fはそれぞれWALとコピー先が格納される変数です。
archive_timeout アーカイビングを試みるタイムアウト時間です。推奨値は60秒程度とされ、もし、それ以上に短い間隔を指定し素早いWAL転送を行いたいならばアーカイビングではなくストリーミングを行う事が推奨されています。

正常系 動作確認

アーカイブの出力先ディレクトリを作成します。

NFSサーバの構築方法については説明を省略します。

mkdir -p /nfs/postgres/wal
chown -R postgres:postgres /nfs/postgres

postgresql.confを以下のように編集します。

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

 <omitted>

archive_mode = on
archive_command = 'cp -p %p /nfs/postgres/wal/%f'
archive_timeout = 60

設定を反映させます。

systemctl restart postgresql-13.service

何らかの更新処理を発生され、WALを出力します。

createdb test
/usr/pgsql-13/bin/pgbench -i test
/usr/pgsql-13/bin/pgbench -c 5 -t 100000 test

アーカイブ領域にログがコピーされた事を確認します。

[root@centos10 ~]# ls -l /nfs/postgres/wal/
合計 81920
-rw------- 1 postgres postgres 16777216 12月 18 18:02 000000010000000000000004
-rw------- 1 postgres postgres 16777216 12月 18 18:03 000000010000000000000005
-rw------- 1 postgres postgres 16777216 12月 18 18:04 000000010000000000000006
-rw------- 1 postgres postgres 16777216 12月 18 18:07 000000010000000000000007
-rw------- 1 postgres postgres 16777216 12月 18 18:09 000000010000000000000008
[root@centos10 ~]# 

異常系 動作確認

NFSサーバに障害が発生した場合の挙動について考察します。まず、NFSサーバに障害を発生させます。

systemctl stop nfs-server.service

何らかの更新処理を発生され、WALを出力します。

/usr/pgsql-13/bin/pgbench -i test
/usr/pgsql-13/bin/pgbench -c 5 -t 100000 test

wal_logが転送されたかどうかはpg_wal/archive_status/ディレクトリ上のファイルで管理されます。doneと書かれているのが転送が完了したファイルで、readyと書かれているのが転送可能な状態であるものの転送が完了していないものを表します。

[root@centos10 ~]# ls -l /var/lib/pgsql/13/data/pg_wal/archive_status/
合計 0
-rw------- 1 postgres postgres 0 12月 18 18:09 000000010000000000000008.done
-rw------- 1 postgres postgres 0 12月 18 18:14 000000010000000000000009.done
-rw------- 1 postgres postgres 0 12月 18 18:14 00000001000000000000000A.done
-rw------- 1 postgres postgres 0 12月 18 18:15 00000001000000000000000B.ready
-rw------- 1 postgres postgres 0 12月 18 18:16 00000001000000000000000C.ready
[root@centos10 ~]#

NFSサーバを復旧させてみます。

systemctl start nfs-server.service

archive_statusが全てdoneに変わります。

[root@centos10 ~]# ls -l /var/lib/pgsql/13/data/pg_wal/archive_status/
合計 0
-rw------- 1 postgres postgres 0 12月 18 18:14 00000001000000000000000A.done
-rw------- 1 postgres postgres 0 12月 18 18:15 00000001000000000000000B.done
-rw------- 1 postgres postgres 0 12月 18 18:16 00000001000000000000000C.done
-rw------- 1 postgres postgres 0 12月 18 18:17 00000001000000000000000D.done
-rw------- 1 postgres postgres 0 12月 18 18:17 00000001000000000000000E.done
-rw------- 1 postgres postgres 0 12月 18 18:18 00000001000000000000000F.done
[root@centos10 ~]# 

WALがNFS上に転送されている事を確認します。

[root@centos10 ~]# ls -l /nfs/postgres/wal/
合計 229376
-rw------- 1 postgres postgres 16777216 12月 18 18:02 000000010000000000000004
-rw------- 1 postgres postgres 16777216 12月 18 18:03 000000010000000000000005
-rw------- 1 postgres postgres 16777216 12月 18 18:04 000000010000000000000006
-rw------- 1 postgres postgres 16777216 12月 18 18:07 000000010000000000000007
-rw------- 1 postgres postgres 16777216 12月 18 18:09 000000010000000000000008
-rw------- 1 postgres postgres 16777216 12月 18 18:14 000000010000000000000009
-rw------- 1 postgres postgres 16777216 12月 18 18:14 00000001000000000000000A
-rw------- 1 postgres postgres 16777216 12月 18 18:15 00000001000000000000000B
-rw------- 1 postgres postgres 16777216 12月 18 18:16 00000001000000000000000C
-rw------- 1 postgres postgres 16777216 12月 18 18:17 00000001000000000000000D
-rw------- 1 postgres postgres 16777216 12月 18 18:17 00000001000000000000000E
-rw------- 1 postgres postgres 16777216 12月 18 18:18 00000001000000000000000F
-rw------- 1 postgres postgres 16777216 12月 18 18:19 000000010000000000000010
-rw------- 1 postgres postgres 16777216 12月 18 18:19 000000010000000000000011
[root@centos10 ~]# 
タイトルとURLをコピーしました