データベースを触ってるときって、すごくシンプルに見えるよね:行を追加したり、レコードを更新したり、クライアントを削除したり。でも、そのシンプルさの裏には、めっちゃ複雑でよく考えられた仕組みが隠れてるんだ。実際にデータってどこに保存されてるの?PostgreSQLはどうやって、サーバーが急に落ちてもデータを失わないようにしてるの?
理解するには、2つのキーポイントを押さえよう:データ(テーブル、インデックス、システム情報)が物理的にどこにあるのか、そしてそのデータを守る仕組み ― トランザクションログ、つまりWAL(Write-Ahead Logging)がどう動くのか。
PostgreSQLのデータベース全体は、data_directoryっていう特別なディレクトリの中にファイルのセットとして保存されてる。だいたいこんな場所にあるよ:
/var/lib/postgresql/17/main
このフォルダの中に、データベースの心臓部が全部詰まってる:テーブルも、インデックスも、メタ情報も、設定も。WALログもここにある ― これが最初に全ての変更を受け止める仕組み。データがディスク上のテーブルに書き込まれる前に、まずWALに記録される。これは下書きみたいなもので、データベースが一歩一歩を記録して、もし何かトラブルがあっても、最後の操作までちゃんと復元できるようになってる。
この仕組みのおかげで、PostgreSQLはどんな不安定な状況でも信頼性と耐障害性をキープできるんだ。
テーブル
各テーブルは物理的には別々のファイルか、ファイルのセットになってる。これらのファイルはbase/サブディレクトリの中にある。構造はだいたいこんな感じ:
$PGDATA/base/
├── 16384/
│ ├── 12345 ← テーブル
│ ├── 12346 ← インデックス
│ └── ...
16384― これはデータベースの内部ID(OID)だよ。12345― これは特定のテーブルのID。
テーブルが大きい場合、PostgreSQLは1GBごとにセグメントに分割する:
12345
12345.1
12345.2
...
ファイルの中身はCSVみたいな「行」じゃなくて、8KBごとの「バイナリページ」形式になってる。
WAL: Write-Ahead Logging ― ただの「ログ」じゃない
次は、PostgreSQLの中でも超重要で、よく誤解されがちな部分 ― WAL、つまりWrite-Ahead Loggingについて。名前にログって入ってるけど、WALは普通のテキストログファイル(エラーログやクエリログみたいなやつ)じゃない。これはデータの一貫性とリカバリのための超重要な仕組みで、ファイルシステムの低レベルな変更を扱ってる。
WALはイベントのレポートじゃなくて、PostgreSQLがこれからデータに対してやる全ての変更を事前に記録するもの。しかもこの記録は、実際にテーブルがディスクで変更される前に行われる。だからwrite-ahead ― 「先に書く」って意味なんだ。
たとえば新しい行をテーブルに挿入するとき、PostgreSQLは:
- いきなりディスク上のテーブルを更新しない ― それだと遅いし危ないから。
- まずWALに「この行を追加するよ」って記録する。
- その後、都合のいいタイミング(たとえばバックグラウンドプロセスで)で、実際にデータがテーブルに書き込まれる。
これはまるで銀行の小切手みたいなもの:まずサインして(WAL)、その後で銀行が口座を更新する(テーブル)。もし何かトラブルがあっても、小切手は手元にあるから、もう一度やり直せる。
WALのフォーマットと構造
- WALファイルはバイナリ形式で保存されてる。
- 各ファイルは厳密に順序付けられた操作のストリームで、データページやインデックス構造、コミットなどの内部変更を記述してる。
- 1つのWALファイルのサイズは固定で、デフォルトだと16MB。
ポイント:WALには「SQLコマンド」や「テーブルの行」みたいなものは入ってない。PostgreSQLエンジン向けの命令が入ってて、ページごとにどう変更を再現するかが書かれてる。
障害が起きたらどうなる?
もしPostgreSQLサーバーが突然落ちたとしても ― たとえば急な停電とか ― 全部パーにはならない。次に起動したとき、データベースは慌てずに、ディスクから最後に保存された「安定した」データのバージョンを読み込む。その後、トランザクションログ(WAL)を使って、残ってる最新の変更を丁寧に「巻き戻し」て、まだメインファイルに反映されてなかった操作を適用する。結果として、データベースは完全に一貫した状態に復元されて、まるで何もなかったかのようになるんだ。
WALの追加機能
Point-In-Time Recovery(PITR) WALファイルを保存しておけば、2つのフルバックアップの間のどんな時点にもデータベースを復元できる。
ストリーミングレプリケーション PostgreSQLはWALレコードをリアルタイムで別サーバーに送ることができる。これでホットスタンバイ ― メインと同期したデータベースのコピー ― を作れる。
増分リカバリ フルバックアップと組み合わせれば、WALで変更分だけを復元できるから、全データベースを丸ごとコピーし直す必要がない。
バイナリバックアップの作成:pg_basebackup
pg_dumpにちょっと慣れてるなら、論理バックアップ(データベース構造やデータをSQLクエリとしてコピーするやつ)にはピッタリだって知ってるよね。でも、物理バックアップが必要なときはどうする?たとえば、データベースファイルを丸ごとミラーコピーしたい場合とか。そんなときはpg_basebackupの出番!
pg_basebackupは、PostgreSQLのデータを物理的にコピーできるツール。特に大規模なデータベースで、効率よくリカバリを管理したいときに便利。pg_basebackupの最大のメリットは、とにかく速いこと!
pg_basebackupコマンドの基本構文
pg_basebackupを使うには、まずコマンドの形を知ろう。ターミナルで実行する基本形はこんな感じ:
pg_basebackup -D /backup_directory -F tar -z -P
これが何をしてるか分解してみよう:
-D /backup_directory― バックアップファイルを保存するディレクトリを指定。-F tar― データのフォーマット。tarオプションは.tar形式のアーカイブファイルを作る。plainを使えば、データベースのファイル構造そのままでもOK。-z― バックアップを圧縮する。ディスク容量の節約になるし、バックアップが小さいとちょっと嬉しいよね!-P― 進捗状況をリアルタイムで表示。これで「ちゃんと動いてる?」って不安にならずに済む!
使い方の例:
pg_basebackup -D /backups/university_backup -F tar -z -P
このコマンドを実行すると、指定した/backups/university_backupディレクトリに.tar形式のバックアップができるよ。
pg_basebackupを使うメリット
効率的: 増分バックアップなら、変わってないデータを重複して保存しないから、時間もディスクも節約できる。
使いやすさ: pg_basebackupはWALファイルも含めて全部自動で処理してくれる。
信頼性: PostgreSQLの仕組みと連携してるから、pg_basebackupで作ったバックアップは正確な全データベースのコピーで、簡単にリストアできる。
使い方の例
じゃあ、実際にやってみよう。下に、PostgreSQLデータベースのバックアップをpg_basebackupで作るリアルな例を載せてるよ。基本的なバックアップの作り方、圧縮の追加方法、トランザクションログ(WAL)のアーカイブを有効にして「任意の時点へのリカバリ」を可能にする方法も紹介。初心者にも上級者にも使えるコマンドだよ。
基本的なバックアップの作成
pg_basebackup -D /backups/full_backup -F tar -z -P
結果:.tarアーカイブ形式のフルデータベースバックアップ。
圧縮とフォーマットの設定
高圧縮レベルでバックアップを作る例:
pg_basebackup -D /backups/full_backup -F tar -z -Z 9 -P
ここで-Z 9は圧縮レベル(最大は9)を指定してる。
WALのアーカイブ
WALのアーカイブを設定すれば、データベースをどんな時点にも復元できる。WALバックアップ用のコマンド例:
pg_basebackup -D /backups/incremental_backup -F tar -z -P --wal-method=archive
GO TO FULL VERSION