pg_upgrade
NTT オープンソースソフトウェアセンタ 笠原 辰仁
はじめに
PostgreSQLでは、定期的なバージョンアップが行われます。バージョンアップには2種類あり、バージョン名 (x.y.z) の x または y が変化するメジャーリリース (8.3 → 8.4) と、z が変化するマイナーリリース (8.3.6 → 8.3.7) です。メジャーバージョンがアップするとDBクラスタの互換性がなくなるため、pg_dump等によるダンプを行い、新版のDBクラスタにデータをリストアする処理が必要です。
このダンプの取得とリストアは、非常に大きなデータを持つシステムでは長時間かかるため厄介でした。この作業が面倒で、古いバージョンを使い続けている方も多いのではないでしょうか?このようなダンプやリストア処理を不要にし、使用中のDBクラスタをそのまま新しいバージョンのPostgreSQLでも使い続けられるようにしてくれるのが、pg_upgrade という contrib モジュールです。
なお、pg_upgrade は PostgreSQL のバージョン 8.3 以上のDBクラスタから、PostgreSQL 9.0以上へアップグレードするケースに対応しています。8.2 から 8.3 や 9.0 へ、また 8.3 から 8.4 へ、といった移行には使用できませんので注意して下さい。
pg_upgradeについて
移行モードについて
pg_upgradeでは、3つのモードが用意されています。
- 移行可否の確認モード
- 実際に移行はせず、pg_upgradeによる移行が可能かをチェックするだけのモード。-c (or --check) オプションを付与して実施
- リンクによる移行モード
- 旧版のデータベースクラスタと新版のデータベースクラスタでユーザデータをハードリンクにより共有するモード。-k (--link)オプションを付与して実施
- コピーによる移行モード
- 旧版のデータベースクラスタから新版のデータベースクラスタへユーザデータをコピーするモード。明示的なオプションを付与しないとこのモードで実施
移行は主にリンクかコピーによって行います。ディスク容量に余裕が無い場合はリンクモード、旧版もデータベースクラスタも残しておきたい場合はコピーモード、と使い分けると良いでしょう。リンクモードの場合、新版のデータベースクラスタを立ち上げてしまうと、旧版のデータベースクラスタが実質的に使えなくなるので、旧版に戻すことを考慮するならばコピーモードを使うと安心です。
移行の所要時間
pg_upgradeを使うとどれくらいバージョンアップの所要時間が短縮されるのでしょうか?開発者のBruce氏の資料では、下記の様に4倍から400倍!という高速化が図れることが報告されています。
移行方法 | 所要時間(分) |
---|---|
dump/restore(通常の方法) | 300 |
dump/パラレルrestore(8.4からの機能) | 180 |
pg_upgrade (コピーモード) | 44 |
pg_upgrade (リンクモード) | 0.7 |
PostgreSQLのアップグレードについては、pg_dump/リストア、pg_upgradeのほか、Slony-Iに頼るという方法もあります。それぞれについて、ざっくり下記の様な使い分け指針があります。
- 移行に際してPostgreSQLの停止ができない場合 → Slony-I
- 移行に際してPostgreSQLが停止できる
- 移行DBのサイズが小さい(十数GB以下) → pg_dumpall
- 移行DBのサイズが大きい(十数GB以上)
- 停止時間が大きくても構わない → pg_dumpall or pg_upgrade
- 停止時間をなるべく抑えたい → pg_upgrade
移行に際しての制約
マニュアルにも記述されていますが、pg_upgrade ではいくつか制約があります。
8.3, 8.4 共通
PostgreSQL ビルド時の configure オプション、initdb 時のオプションのいくつかは統一しておく必要があります。注意が必要なのは、configureの--enable/disable-integer--datetimes オプション、initdb の locale オプションです。これらが異なる場合、pg_upgrade を使用することはできません。特に、バージョン 9.0 から integer--datetimes オプションがデフォルトで有効になっているため、ここの不一致で pg_upgrade による移行ができないことが多いです。
8.3からの移行
tsquery 型を含んだテーブル、もしくはname型のカラムが先頭(一番初め)に定義されていないテーブルはチェック段階でエラーになります。この場合、もし、制約に該当するテーブルが少量しかないのであれば、該当のテーブルのみ pg_dump 等で移行し、その他を pg_upgrade に任せるという方法があります。ただ、通常の使い方ではこれらがデータに含まれることは少ないでしょう。
tsvector 型のテーブルは、移行後にデータの再作成が必要になります。再作成用のシェルは pg_upgrade が生成してくれます。
GINインデックスやハッシュインデックスは、移行後にインデックスの再作成が必要になります。再作成用のシェルは pg_upgrade が生成してくれます。
pg_upgrade のインストール
pg_upgrade は通常の contrib モジュールと同様にコンパイルしインストールします。RPM を使っている場合は特に注意はいりませんが、ソースからコンパイル・インストールする場合は、contrib/pg_upgrade と contrib/pg_upgrade_support の両方が必要です。なお、特にDBへ何かしらのSQLファイルを流し込む、といった作業は必要ありません。
pg_upgrade の実行
pg_upgrade の実施時には、基本的に「移行元 (旧版) と移行先 (新版) のPostgreSQLのDBクラスタのパスと実行ファイル(pg_ctlなどのインストール先)のパス」を指定することになります。オプションで下記にの様に指定します。
- -dオプション : 旧バージョンのDBクラスタのパス
- -Dオプション : 新バージョンのDBクラスタのパス
- -bオプション : 旧バージョンのPostgreSQL実行ファイルのパス
- -Bオプション : 新バージョンのPostgreSQL実行ファイルのパス
正しいパスを確認しておきましょう。また、-l オプションでさらに詳細なログを取ることができますので、なるべく付与するようにしましょう。
pg_upgradeの移行フェーズについて
pg_upgrade は主に以下の2つのフェーズで移行を実施します。
- 移行が可能かを判断する互換性のチェック
- 上記ログのPerforming Consistency Checksのフェーズ
- ここで処理が中断した場合、ビルドオプションやinitdbの互換性がない
- ファイルの変更/コピー等の実施
- 上記ログのPerforming Migrationのフェーズ
- ここで処理がwarningで中断した場合は、移行終了後にpg_uprgadeが出力するメンテナンス用のシェルを実施する
なお、ファイルの変更/コピーのフェーズでfatal等のエラーにより処理が中断した場合、新版のDBクラスタは一旦破棄します。旧版のDBクラスタについては、global/pg_controlに.oldが付与されているので、それを取り除く(ファイル名の変更)必要があります。
互換性チェックのフェーズ
では、コピーによる移行モードを例に、DBフェーズ別の実際の流れを見て行きましょう。まず、pg_upgrade を実行すると以下の様なログがコンソールに出力されます。
$ pg_upgrade \ -d /base/PG84/ -D /base/PG90 \ -b /usr/local/pgsql844/bin/ -B /usr/local/pgsql900/bin/ \ -l /tmp/up.log Performing Consistency Checks ----------------------------- Checking old data directory (/base/PG84/) ok Checking old bin directory (/usr/local/pgsql844/bin) ok Checking new data directory (/base/PG90) ok Checking new bin directory (/usr/local/pgsql900/bin) ok Checking for reg* system oid user data types ok Checking for /contrib/isn with bigint-passing mismatch ok Checking for large objects ok Creating catalog dump ok Checking for presence of required libraries ok | If pg_upgrade fails after this point, you must | re-initdb the new cluster before continuing. | You will also need to remove the ".old" suffix | from /base/PG84/global/pg_control.old.
上記までが互換性チェックのフェーズです。 互換性チェック時に制約にひっかかるものがあった場合は例えば以下の様なログが出ます。
Performing Consistency Checks ----------------------------- (略) old and new cluster lc_collate values do not match
- Date/Timestamp型のフォーマット(enable/disable-integer--datetimes)不一致
Performing Consistency Checks ----------------------------- (略) Old and new pg_controldata date/time storage types do not match.
- ロケールの不一致
- name型が先頭で定義されていないテーブルがある時(8.3から移行時)
Performing Consistency Checks ----------------------------- (略) Checking for invalid 'name' user columns fatal
データコピーのフェーズ
次に実際にデータのコピーが実施されているログを示します。
Performing Migration -------------------- Adding ".old" suffix to old global/pg_control ok Analyzing all rows in the new cluster ok Freezing all rows on the new cluster ok Deleting new commit clogs ok Copying old commit clogs to new server ok Setting next transaction id for new cluster ok Resetting WAL archives ok Setting frozenxid counters in new cluster ok Creating databases in the new cluster ok Adding support functions to new cluster ok Restoring database schema to new cluster ok Removing support functions from new cluster ok Restoring user relation files ok Setting next oid for new cluster ok Creating script to delete old cluster ok Checking for large objects ok Upgrade complete ---------------- | Optimizer statistics is not transferred by pg_upgrade | so consider running: | vacuumdb --all --analyze-only | on the newly-upgraded cluster. | Running this script will delete the old cluster's data files: | /var/lib/pgsql/delete_old_cluster.sh
データ移行時に制約にひっかかるものがあった場合は例えば以下の様なログが出ます。
Performing Migration ----------------------------- (略) Checking for tsvector user columns warning | Your installation contains tsvector columns. | The tsvector internal storage format changed | between your old and new clusters so the tables | must be rebuilt. The file: | /var/lib/pgsql/rebuild_tsvector_tables.sql | when executed by psql by the database super-user | will rebuild all tables with tsvector columns.
上記の場合は移行自体には問題はありませんが、制約に一部ひっかかっており、移行後に"rebuild_tsvector_tables.sql"を実施する必要があります。
- tsvector型のデータを含むテーブルがある時(8.3から移行時)
全ての項が ok となり、"Upgrade complete"が表示されれば、無事に移行完了です。最後に、pg_upgradeの実施ディレクトリに"delete_old_cluster.sh"が出力されます。これは、旧版のDBクラスタを削除するシェルです。もし、旧版のDBクラスタが必要ない場合は、このシェルを実施します。もちろん、シェルを使わず手動で削除しても構いません。
おわりに
PostgreSQLのアップグレードをより簡易に実施できるpg_upgradeを紹介しました。従来のpg_dumpallなどを使った方法より、高速かつ簡単に実施可能です。また、DBクラスタ間の互換性のチェックなども実施できるため、事前のテストなどにも有用です。是非、pg_upgradeを試してみて下さい!