pg_repackでテーブルスペースを移動して容量の危機を脱した2018.5.23
published_at: 2018-05-28
相当の業務ボリュームの増加で、DBサーバー(※0)の容量が危機的になってきた。
対策として、世界に残り40枚(業者談)という高速ディスクのカードを購入し、増設を実施。
その増設領域への実体移動手段として、pg_repack を使用し、当面の問題解消に成功。
とある運用事例として世の中の役に立てばと思い、投稿。
- (※0)
- PostgreSQL系のRDBMSで、付属のGUIツールがある有償製品を使用している
はじめに
テーブルスペース について
- テーブル空間を使用することで、PostgreSQLのディスクレイアウトを制御することができる。ボリュームの容量不足時に対策可能。
(PostgreSQL 9.4.5文書 21.6. テーブル空間)
pg_repack について
- オンライン中に動作させることができる、テーブルやインデックスの再編成ツール。
調整前の状態
なかなかの逼迫状態
容量(df -h) | サイズ | 使用 | 残り | 使用% | マウント位置 |
---|---|---|---|---|---|
/dev/fioa1 | 2.2T | 1.7T | 464G | 79% | /mnt/fio/(以下略) |
ディスクの増設
シャットダウン前に
増設前にシャットダウンが必要なので準備として以下を実施
- サービスをメンテナンスモードにして外からのアクセスをなくす
- 内部で定期的に実行されるバックグラウンド処理を全て止める
- この時点でWALファイルが出なくなっている状態と想定していたがautovacuumが回っていてなかなか出るのが止まらなかったのでDBMSを停止
- これで完全にWALファイルの出力が止まったので、 バックアップサーバーに念のためWALファイルをコピーして(※1)、シャットダウン。
- (※1)
- 万一の、サーバーが上がってこないケースに備えて。
カード増設、ドライバ・ファームウェアのアップデート
(丸々業者にやってもらいました)
(とはいえ実施タイミングのキュー出しは発注側の指示なので主導的に計画・想定)
(過程で必要になるリモートアクセスコントローラへのログインはWindowsのPCを持参して対応)(※2)
(2回ほどOS再起動をはさみ、使用可能になる)
- (※2)
- 新しいバージョンのものだったのでこのケースでは大丈夫でしたが、古いiDRACなどの場合は仮想コンソールを起動するにはJavaのバージョンに注意が必要。
pg_repack で テーブルスペース移動
増設直後(フォーマット・マウントコマンドは割愛)
容量(df -h) | サイズ | 使用 | 残り | 使用% | マウント位置 |
---|---|---|---|---|---|
/dev/fioa1 | 2.2T | 1.7T | 464G | 79% | /mnt/fio/(以下略) |
/dev/fiob | 3.0T | 33M | 3.0T | 1% | /mnt/fio2/(以下略) |
PostgreSQL起動
設定を確認・調整のうえで起動。
テーブルスペースを作成
/mnt/fio2
配下にテーブルスペース用のディレクトリを作成し、
オーナー・パーミッションを postgres:postgres 700
にしたうえで、
GUIでテーブルスペース space2
を作成。(※3)
なお、レプリケーション先にも同一のディレクトリパスを整備しておかないと、テーブルスペース作成時にレプリケーションが切れる。
- (※3)
- 有償製品ならではのGUIを利用。ちなみに以下のようなSQLに相当(おそらく)
CREATE TABLESPACE space2 LOCATION '/mnt/fio2/(以下略)';
- 有償製品ならではのGUIを利用。ちなみに以下のようなSQLに相当(おそらく)
デフォルトテーブルスペースの変更
今後の書き込み先が space2
となるように以下のクエリを実行
ALTER DATABASE large-db SET default_tablespace TO 'space2';
現在のデフォルトテーブルスペースを確認する方法は、各DBで以下コマンドの実行
SHOW default_tablespace;
もしくはテーブル単位でテーブルスペースを確認できるので新規テーブルに対して以下SQL
SELECT
u.relname AS table_name,
current_database() AS database_name,
t.tablespace AS tablespace_name
FROM
pg_stat_user_tables u
JOIN pg_tables t ON u.relname = t.tablename
WHERE
relname = '(新規テーブル名)';
テーブルスペース移動スクリプト
第1引数にテーブルリスト、第2引数にDB名、第3引数に移動先のテーブルスペースを指定するスクリプトが以下のようになります。
-
num
は進捗を把握する意図の変数、pg_repack 前後の pg_size_pretty 関数は再編成効果を表示する意図のコマンドになります - pg_repack の前の time コマンドは、コンソールに表示されますが流れが速すぎて1つ1つを確認できないかもしれません
# !/bin/bash
tbl=$(cat $1)
db=$2
toSpace=$3
num=0
for t in ${tbl[@]}
do
num=$((num + 1))
echo "----- [$num] ----- ${t}";
psql -U postgres -h localhost -t -c"SELECT pg_size_pretty(pg_total_relation_size('${t}')) AS tbl_size" ${db}
time pg_repack -U postgres -h localhost -d ${db} -t ${t} -s ${toSpace} -S
psql -U postgres -h localhost -t -c"SELECT pg_size_pretty(pg_total_relation_size('${t}')) AS tbl_size" ${db}
echo "";
done
これを、chmod +x exec_repack_mv_space.sh
したうえで 以下のように実行します
./exec_repack_mv_space.sh tbl-list large-db space2
調整後の状態
テーブルスペース移動はメンテナンスの時間のうちで、と思っていましたが時間内にリストが終わり切らず。。
しかしリストが終わるまでスクリプト実行を継続しましたがサービス影響は報告されずに済みました。
影響なく済んだと捉えています。 :sweat_smile:
容量(df -h) | サイズ | 使用 | 残り | 使用% | マウント位置 |
---|---|---|---|---|---|
/dev/fioa1 | 2.2T | 1.4T | 770G | 65% | /mnt/fio/(以下略) |
/dev/fiob | 3.0T | 208G | 2.8T | 7% | /mnt/fio2/(以下略) |
おわりに
- 今後も空き容量を見て pg_repack の運用が必要になりそうだが、当面は凌いだと言えそう。
- かなり強力でありがたい運用ツールとして利用していきそう。
- 容量が膨らみそうなDBでも、最初からテーブルスペースを利用することで長期的な稼働が見込めそう。
- 運用にまあまあ神経使いそうですが。
- 感じた pg_repack の傾向など(個人の見解です)
- 実行時はCPU負荷がそれなりにかかる感じ。サービス影響に適度に気をつけたほうがよさそう。
- 大きいテーブルの pg_repack はかなり時間がかかるようだ。。
- 処理にはコア1つしか使わないようだ。
- リソースが潤沢であればいくらか並列実行してよさそう。PostgreSQLの傾向?
その他
- 現在のテーブルスペースを把握する方法があまりないようで、メタコマンド
¥l+
で表示されるDB毎の Tablespace は当初のもののようだ。 - テーブルスペースの移動をしない pg_repack を実行する場合、
exec_repack_mv_space.sh
から-s ${toSpace} -S
を外せばよいかと。 - pg_repack のインストール方法については別立ての記事に。(もしくは公式をご参照。。)
- 成功裏に増設・移動が少しできたが、事前の検証・把握を十分に行ったための結果だと思っている。
- 予行演習・小規模実行が功を奏した。やはり、準備が大切。
Discussion