-
2022-12-20 PostgreSQLPostgreSQL パラメータ
もし運用中に max_wal_size を下げたら、過剰分の WAL ファイルはどうなるのか
前回から随分と時間が空いてしまいましたが、本記事では、運用中に max_wal_size を減少させた場合の挙動について、検証した結果をご報告したいと思います。
検証の概要
WAL ファイルはチェックポイント処理で削除(再利用)されます。
チェックポイント処理が発生するタイミングとしてはいくつかありますが、max_wal_size 以上の WAL ファイルが作成される場合にも、チェックポイント処理が行われます。
この max_wal_size 以上の WAL ファイルが作成されること(いわゆる WAL あふれ)を契機としたチェックポイント処理は、緊急的なチェックポイント処理となります。
緊急的な、ということから、できるだけ発生させない方がよいとされています。
そこで、合計で 128 MB の WAL ファイルが存在する状態で、max_wal_size を 64 MB に変更した場合に、どのような挙動になるのでしょうか。
実際に検証して確認した結果を下記に記載いたします。
環境
今回の検証は下記の環境で行いました。
- Ubuntu 22.04.1
- PostgreSQL 14.6
検証
1. WAL ファイルの出力状況を確認する
まず WAL ファイルの出力状況を確認します。
WAL ファイルはデフォルトでは、データベースクラスタの pg_wal ディレクトリ配下に出力されます。
$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:31 pg_wal/00000001000000000000004F
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000050
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000051
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- WAL ファイルが max_wal_size の上限分、出力されていることを確認できました。
- WAL ファイルは 1 個 16 MB ですので、128 MB = 16 MB * 8 個 となります。
2. max_wal_size を 128 MB から半分の 64 MB に変更する
postgresql.conf を修正するか、ALTER SYSTEM コマンドで、max_wal_size を 128 MB から 64 MB に変更します。
今回は ALTER SYSTEM コマンドで変更します。
max_wal_size の変更は、再起動不要で反映できます。
postgres=# show max_wal_size;
max_wal_size
--------------
128MB
(1 row)
- 現在の設定が 128 MB であることを確認しました。
postgres=# ALTER SYSTEM SET max_wal_size = '64MB';
ALTER SYSTEM
postgres=# SELECT pg_reload_conf();
pg_reload_conf
----------------
t
(1 row)
postgres=# show max_wal_size;
max_wal_size
--------------
64MB
(1 row)
- 無事に 64 MB に変更できました。
3. WAL ファイルの出力状況を確認する
では、max_wal_size の変更後、WAL ファイルの個数がどうなっているかを確認します。
$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:35 pg_wal/00000001000000000000004F
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000050
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000051
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- 変更前と変わらず、WAL ファイルは 8 個存在していました。
4. チェックポイント処理を実行する
前述のとおり、WAL ファイルはチェックポイント処理で削除(再利用)されますので、チェックポイント処理を明示的に実行してどうなるかを確認します。
postgres=# CHECKPOINT;
CHECKPOINT
- チェックポイントが行われました。
もう一度、WAL ファイルの出力状況を確認します。
$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:36 pg_wal/00000001000000000000004F
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000050
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000051
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- チェックポイント処理前と変わらず、WAL ファイルが 8 個存在しています。
単純に max_wal_size を減少させて、チェックポイント処理を行うだけでは、過剰分(max_wal_size 以上)の WAL ファイルは削除対象とならないようです。
5. WAL ファイルの書き込み位置を強制的に新しいファイルにする
チェックポイント処理で削除されないというのであれば、WAL ファイルの書き込み位置を新しい WAL ファイルに変更すると、どうなるかを確認します。
WAL ファイルの書き込み位置を新しい WAL ファイルに変更するには、 pg_switch_wal() 関数を実行します。
postgres=# SELECT pg_switch_wal();
pg_switch_wal
---------------
0/4F219E18
(1 row)
- pg_switch_wal () 関数を実行し、WAL ファイルを強制的に出力しました。
WAL ファイルの状態を見てみます。
$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:36 pg_wal/00000001000000000000004F
-rw------- 1 postgres postgres 16M Dec 13 11:37 pg_wal/000000010000000000000050
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000051
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- WAL レコードの出力先ファイルが 00000001000000000000004F から 000000010000000000000050 になりました。
- pg_switch_wal () 関数を実行しても、WAL ファイルは 8 個のままでした。
6. チェックポイント処理を実行する
この状態でチェックポイント処理を実行して、WAL ファイルの出力状況を確認します。
postgres=# CHECKPOINT;
CHECKPOINT
$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:38 pg_wal/000000010000000000000050
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000051
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- チェックポイント処理によって、00000001000000000000004F が削除され、WAL ファイルが 7 個となりました。
ようやく 1 つの WAL ファイルが削除されました。
7. もう一度 WAL ファイルの書き込み位置を強制的に新しいファイルにする
WAL ファイルの書き込み位置を新しくすると、チェックポイント処理で WAL ファイルが 1 つ削除されました。
となると、WAL ファイル 2 つ分、書き込み位置を新しくすると、その後のチェックポイント処理で 2 つの WAL ファイルが削除されそうですので、実際に確認します。
postgres=# SELECT pg_switch_wal();
pg_switch_wal
---------------
0/50000160
(1 row)
postgres=# CREATE TABLE test_table (i INTEGER);
CREATE TABLE
postgres=# SELECT pg_switch_wal();
pg_switch_wal
---------------
0/51000000
(1 row)
- WAL ファイルへ書き込みが行われていない状態で pg_switch_wal () 関数を実行しても、新しいファイルへ書き込み位置が移動しません。
- そのため WAL レコードを発生させるために CREATE TABLE しています(WAL レコードを発生させるのであれば、どんな処理でも問題ありません)。
2 つ分、書き込み位置が進んだのでチェックポイント処理を実行して、WAL ファイルの状態を確認します。
postgres=# CHECKPOINT;
CHECKPOINT
postgres@server:~/14$ ls -lh pg_wal/*
-rw------- 1 postgres postgres 16M Dec 13 11:39 pg_wal/000000010000000000000052
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000053
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000054
-rw------- 1 postgres postgres 16M Dec 13 11:28 pg_wal/000000010000000000000055
-rw------- 1 postgres postgres 16M Dec 13 11:30 pg_wal/000000010000000000000056
pg_wal/archive_status:
total 0
- 000000010000000000000050 と 000000010000000000000051 が削除されました。
- 予想どおり、WAL ファイルが 2 つ削除され、合計 5 個となりました。
まとめ
感覚的には max_wal_size を減少させたら「すぐにチェックポイント処理が行われて過剰分の WAL ファイルがすべて削除される」という予想だったのですが、「チェックポイント処理で削除されるのは、新しく発生した WAL ファイルの個数分」というのは、正直なところ意外な結果となりました。
公式ドキュメント( https://www.postgresql.jp/document/14/html/wal-configuration.html )では、max_wal_size とチェックポイントの関係性は
サーバのチェックポインタプロセスは、自動的にチェックポイントを時々実行します。 checkpoint_timeout秒が経過するか、またはmax_wal_sizeに達するか、どちらかの条件が最初に満たされるとチェックポイントが開始されます。
という、ざっくりとした表現となっております。
やはり実際に検証してみて、どのような挙動となるのかを確認するのが(時間はかかりますが)必要ということを再認識しました。
max_wal_size を運用中に下げたいというケースは、(あまりないと思いますが)例えば、ディスクの空き領域が少ないので、max_wal_size を一時的に下げて空き領域を作りたい、とかいう場合などが挙げられます。
WAL ファイル関連の仕様や仕組みは、PostgreSQL を運用する上で重要な部分となっていますので、色々とノウハウを溜めておくと緊急時にも慌てなくて済むかと思います。