-
2023-10-01 PostgreSQL
非排他的バックアップを実行するシェルスクリプトの改善
非排他的バックアップを実行するシェルスクリプト
以前の記事( PostgreSQL 15 で廃止となった排他的バックアップについて )で、非排他的バックアップのサンプルスクリプトを記載しました。
その記事内では psql の -c オプションを複数記述して、非排他的バックアップを実現しているのですが、-c オプションが並びすぎて少し保守性が悪いと感じていました。
シェルスクリプトと psql の仕様を利用した改善を検討
シェルスクリプトでは「ブロックで囲んだ処理の結果をまとめて、リダイレクトやパイプに渡せる」ということを新たに知りました。
また、psql には SQL 文をパイプで受け取って実行できる仕様があります。
この 2 つの仕様を組み合わせることで、非排他的バックアップスクリプトを改善できるか検討しました。
ブロックで囲んだ処理の結果を psql にパイプで渡すとどうなるのか
改善の前に、簡単なシェルスクリプトを作成し、新しく知った仕様について挙動を確認します。
具体的には、下記のようなシェルスクリプトを作成しました。
{
echo "SELECT current_timestamp;"
sleep 5
echo "SELECT current_timestamp;"
} | psql
このシェルスクリプトを実行した際の挙動は
- SELECT current_timestamp を実行
- sleep で 5 秒停止
- SELECT current_timestamp を実行
となりました。
sleep で停止してから 2 度目の SQL が実行されていますので、想定通りの挙動となっていることを確認できました。
非排他的バックアップを実行するシェルスクリプトの改善
この仕様を利用して、以前のバックアップスクリプトを下記のように改善しました。
{
# 1. pg_backup_start 関数の実行
echo "SELECT * FROM pg_backup_start('test', false);"
# 2. バックアップ処理の開始
tar -cvzf ${BACKUP_DIR}/basebackup_15a.tar.gz ${PGDATA} > ${BACKUP_DIR}/backup_result.txt
# 3. pg_backup_stop 関数の結果を受け取る一時テーブルを作成
echo "CREATE TEMP TABLE backup_stop_result (lsn pg_lsn, labelfile TEXT, spcmapfile TEXT);"
# 4. pg_backup_stop 関数の実行
echo "INSERT INTO backup_stop_result SELECT * FROM pg_backup_stop();"
# 5. pg_backup_stop 関数の結果出力用に出力フォーマットを変更
echo "\pset tuples_only on"
echo "\pset format unaligned"
# 6. pg_backup_stop 関数の結果(labelfile)を backup_file に出力
echo "\o ${BACKUP_DIR}/backup_label "
echo "SELECT labelfile FROM backup_stop_result; "
echo "\o"
# 7. pg_backup_stop 関数の結果(spcmapfile)を tablespace_map に出力
echo "\o ${BACKUP_DIR}/tablespace_map "
echo "SELECT spcmapfile FROM backup_stop_result; "
echo "\o"
} | psql
- psql で実行したい SQL 文を echo します。
- psql で実行しない SQL 文以外の処理には、リダイレクトを記述します。
- バックアップ処理の結果が psql に渡されないように、backup_result.txt というファイルにリダイレクトしています。
- ブロックの後にパイプをつけて、psql を実行します。
さらに改善
上記の単純にブロックで囲んだだけでは、処理の途中でブロックから抜けることができません。
例えば、バックアップ処理でエラーが発生した場合に、後続の処理を行わずに処理から抜けたい場合など、処理の途中でブロックから抜けたい場面があります。
その場合には、処理を関数にすることでブロックから抜けることができるようになります。
具体的には下記のような処理の流れになります。
function start_backup () {
# 1. pg_backup_start 関数の実行
echo "SELECT * FROM pg_backup_start('test', false);"
# 2. バックアップ処理の開始
tar -cvzf ${BACKUP_DIR}/basebackup_15a.tar.gz ${PGDATA} > ${BACKUP_DIR}/backup_result.txt
if [ $? -gt 0 ]; then
# エラーが発生している場合には処理から抜ける
return
fi
# 3. pg_backup_stop 関数の結果を受け取る一時テーブルを作成
echo "CREATE TEMP TABLE backup_stop_result (lsn pg_lsn, labelfile TEXT, spcmapfile TEXT);"
# 4. pg_backup_stop 関数の実行
echo "INSERT INTO backup_stop_result SELECT * FROM pg_backup_stop();"
# 5. pg_backup_stop 関数の結果出力用に出力フォーマットを変更
echo "\pset tuples_only on"
echo "\pset format unaligned"
# 6. pg_backup_stop 関数の結果(labelfile)を backup_file に出力
echo "\o ${BACKUP_DIR}/backup_label "
echo "SELECT labelfile FROM backup_stop_result; "
echo "\o"
# 7. pg_backup_stop 関数の結果(spcmapfile)を tablespace_map に出力
echo "\o ${BACKUP_DIR}/tablespace_map "
echo "SELECT spcmapfile FROM backup_stop_result; "
echo "\o"
}
start_backup | psql
まとめ
以上が非排他的バックアップスクリプトに対して、新しく知ったシェルスクリプトの仕様を利用して改善した結果となります。
ただ、改善後のシェルスクリプトも echo で SQL 文を出力する、という少し回りくどいやり方となっているので、ヒアドキュメントにしてもよいかもしれません。
また改善に利用できそうな知識を得た際には検討したいと思います。