がじぇ

お金と家電とプログラミングのブログ

PostgreSQLのエラー対応方法(could not write to file "pg_xlog/xlogtemp.28545": No space left on device)

がじぇったー (@hackmylife7) | Twitter

です。

/pgsql/data/pg_log/配下のログファイルに以下のエラーが出力された場合の対応方法についてまとめます。

could not write to file "pg_xlog/xlogtemp.28545": No space left on device

環境は以下の通りです。

そもそもこの事象は何故起こるか

この事象はPostgreSQLによるpg_xlogディレクトリへのWALファイルの書き込み→ストレージの容量不足によって発生します。

# du -sh /usr/local/pgsql/data/* | sort -hr
185G    /usr/local/pgsql/data/pg_xlog
71M /usr/local/pgsql/data/base
14M /usr/local/pgsql/data/pg_log
448K    /usr/local/pgsql/data/global
56K /usr/local/pgsql/data/pg_subtrans
28K /usr/local/pgsql/data/pg_multixact

WALファイルとは何か?

WALファイルとは先行書き込みログ(WAL)のことであり、データベースのデータファイルに行われた全ての変更が記録されています。

主にリストア用の設定となり、postgresql.confのarchive modeをonにしているとこのファイルの作成処理が走ります。

単純にarchive modeをoffにすればそもそもWALファイルの作成処理が走らなくなるのでこのエラーは発生しません。(リカバリできなくなるのでお勧めはしません)

PostgreSQLは常に、クラスタのデータディレクトリ以下のpg_xlog/ディレクトリ内で先行書き込みログ(WAL)を管理しています。 このログはデータベースのデータファイルに行われた全ての変更を記録します。 このログは主にクラッシュ時の安全性を目的としています。 システムがクラッシュしたとしても、最後のチェックポイント以降に作成されたログ項目を"やり直し"することで、データベースを整合性を維持した状態にリストアすることができます。 https://www.postgresql.jp/document/9.4/html/continuous-archiving.html#BACKUP-ARCHIVING-WAL

対応方法

以下の手順で復旧を行います。

  • pg_xlog配下の不要なWALファイルを削除
  • リストアし、Postgresqlプロセスの再起動

pg_xlog配下の不要なWALファイルを削除

/pg_xlog、/pg_xlog/archive_status/配下の不要なファイルを削除します。

削除対象の見分け方は以下のページの対応方法がわかりやすく書かれているので引用させて頂きます。

削除してよいファイルを判別するには pg_xlog の下の archive_status ディレクトリを確認します。ここに「000000010000000000000028.ready」というファイルがあれば「000000010000000000000028」という WALファイルは削除して良いということを表しています。また「000000010000000000000028.ready」ファイルも削除してよいです。したがいまして、対応する「〜.ready」ファイルの無い数個の WALファイルを残して、それ以外の WALファイルを全て削除するという対応になります。 https://powergres.sraoss.co.jp/s/ja/product/win-tech/malfunction9_0.php

上記方法で削除対象を抽出したら不要なファイルの削除作業を行います。 自分の場合はスクリプトで削除作業を行いました。

pg_xlog配下のWALファイルとarchive_status配下の.ready付きのファイルが一致する場合はWALファイルのタイムスタンプが新しいものを数個残してそれ以外を削除してしまいましょう。

タイムスタンプが最新のWALを保管(複数個残した方が良い)

# mv /usr/local/pgsql/data/pg_xlog/000000010000005C0000007C /tmp/

削除スクリプトの作成

# vi /usr/local/pgsql/data/pg_xlog/delete_archive.sh

以下内容の貼り付け

#!/bin/bash

cnt=0
while read line
do
    rm -f $line
done <<END
000000010000002E00000040
000000010000002E00000041
000000010000002E00000042
000000010000002E00000043
000000010000002E00000044
archive_status/000000010000002E00000051.ready
archive_status/000000010000002E00000052.ready
END

スクリプトの実行

# cd /usr/local/pgsql/data/pg_xlog/
# sh delete_archive.sh 

データの確認

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      197G  1.8G  185G   1% /
tmpfs           1.8G     0  1.8G   0% /dev/shm

復旧

# su - postgres
$ /usr/local/pgsql/bin/pg_ctl start
server starting

$ ps -ef | grep postgres
root     28769 28756  0 04:43 pts/1    00:00:00 su - postgres
postgres 28770 28769  0 04:43 pts/1    00:00:00 -bash
root     28970 28947  0 06:26 pts/2    00:00:00 su - postgres
postgres 28971 28970  0 06:26 pts/2    00:00:00 -bash
postgres 29056     1  1 06:34 pts/2    00:00:00 /usr/local/pgsql/bin/postgres
postgres 29057 29056  0 06:34 ?        00:00:00 postgres: logger process
postgres 29059 29056  0 06:34 ?        00:00:00 postgres: checkpointer process
postgres 29060 29056  0 06:34 ?        00:00:00 postgres: writer process
postgres 29061 29056  0 06:34 ?        00:00:00 postgres: wal writer process
postgres 29062 29056  0 06:34 ?        00:00:00 postgres: autovacuum launcher process
postgres 29063 29056  0 06:34 ?        00:00:00 postgres: stats collector process

$ netstat -ant | grep 5432
tcp        0      0 0.0.0.0:5432                0.0.0.0:*                   LISTEN
$

古いWALファイルを丸ごと消してしまった場合

以下のブログの通り初期化が必要です。

hogem.hatenablog.com

以上です。

参考Link