内部構造から学ぶPostgreSQL 設計・運用計画の鉄則 ch11 オンライン物理バックアップ (1/2)

OSS-DBPostgreSQL勉強メモ

出典: 


【準備】前準備

  • WALのアーカイブを有効化しておく

    • postmasterなのでrestart必要
postgres=# SELECT name,setting,context FROM pg_settings WHERE name='archive_mode';
     name     | setting |  context   
--------------+---------+------------
 archive_mode | off     | postmaster
(1 row)
  • 雑に/tmp/archiveにコピーすることにする
archive_mode = on
archive_command = 'cp %p /tmp/archive/'

オンライン物理バックアップの仕組み

  • ベースバックアップ

    • pg_basebackupコマンド
    • 低レベル関数

      • pg_start_backup関数
      • pg_end_backup関数
  • WALファイル

    • pg_wal/
    • アーカイブ

pgstartbackup関数の処理

  • 流れ

    1. 共有メモリ上のステータスを「バックアップ中」にする

      • 複数のベースバックアップが取得されないように
    2. WALを新しいセグメントにスイッチする

      • バックアップ中のWALは別のセグメント
    3. チェックポイント発行、backup_labelファイルを書き出す

      • 開始時刻
      • 特定用ラベル文字列
      • WALファイル名

        • LSNをもとに特定
    4. LSN返却

チェックポイント処理の制御

SELECT pg_start_backup('label', false, false);
  • 第一引数: バックアップラベル 特定用
  • 第二引数: trueなら全力を出す デフォルトfalse

    • falseの場合、checkpoint_completion_targetにしたがって休み休み行う
  • 第三引数: trueなら排他 デフォルトtrue

    • 排他オプションはdeprecated

pgstopbackup関数の処理

  • 流れ

    1. 共有メモリ上のステータスを元に戻す
    2. backup_labelを読み込み、開始LSN位置を取得する
    3. 当該LSNを含むWALレコードを読み出す
    4. WALをスイッチする (A)
    5. バックアップ履歴ファイルを書き出す (B)
    6. (A), (B)のWALファイルがアーカイブされるのを待つ
    7. LSN返却
  • 公式
SELECT * FROM pg_stop_backup(false, true);

WALスイッチ

  • いつWALセグメントが切り替わるか

    • pg_start_backupで一度スイッチ
    • pg_stop_backupで一度スイッチ
  • LSN取得
postgres=# SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn 
---------------------------
 0/16454E8
(1 row)
  • LSNからWALファイル導出
postgres=# SELECT pg_walfile_name(pg_current_wal_insert_lsn());
     pg_walfile_name      
--------------------------
 000000010000000000000001
(1 row)

postgres=# \! ls -lA pg_wal/
total 16388
-rw------- 1 postgres postgres 16777216 Feb 14 14:51 000000010000000000000001
drwx------ 2 postgres postgres     4096 Feb 14 14:49 archive_status
  • ベースバックアップを開始してみる
postgres=# SELECT pg_start_backup('test');
 pg_start_backup 
-----------------
 0/2000028
(1 row)
  • 再度pg_start_backupを試みるとエラー

    • 共有メモリ上のステータスが「バックアップ中」の状態だから
postgres=# SELECT pg_start_backup('test2');
ERROR:  a backup is already in progress
HINT:  Run pg_stop_backup() and try again.
  • pg_start_backupを実行したのでLSNが更新されている
postgres=# SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn 
---------------------------
 0/2000110
(1 row)
  • WALがスイッチされている
postgres=# SELECT pg_walfile_name(pg_current_wal_insert_lsn());
     pg_walfile_name      
--------------------------
 000000010000000000000002
(1 row)

postgres=# \! ls -lA pg_wal/
total 32772
-rw------- 1 postgres postgres 16777216 Feb 14 14:52 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Feb 14 14:52 000000010000000000000002
drwx------ 2 postgres postgres     4096 Feb 14 14:52 archive_status
  • 1がアーカイブ準備できている
postgres=# \! ls -lA pg_wal/archive_status
total 0
-rw------- 1 postgres postgres 0 Feb 14 14:52 000000010000000000000001.ready
  • ベースバックアップ取得終了する

    • ベースバックアップ取得中にスイッチしていたWALのLSNが返る
postgres=# SELECT pg_stop_backup();
NOTICE:  all required WAL segments have been archived
 pg_stop_backup 
----------------
 0/2000138
(1 row)

postgres=# \! ls -lA /tmp/archive
total 32772
-rw------- 1 postgres postgres 16777216 Feb 14 14:55 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Feb 14 14:56 000000010000000000000002
-rw------- 1 postgres postgres      323 Feb 14 14:56 000000010000000000000002.00000028.backup

postgres=# \! ls -lA pg_wal/
total 49160
-rw------- 1 postgres postgres 16777216 Feb 14 14:52 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Feb 14 14:56 000000010000000000000002
-rw------- 1 postgres postgres      323 Feb 14 14:56 000000010000000000000002.00000028.backup
-rw------- 1 postgres postgres 16777216 Feb 14 14:56 000000010000000000000003
drwx------ 2 postgres postgres     4096 Feb 14 14:56 archive_status
  • ベースバックアップ取得中にスイッチしていたWALのファイル名取得
postgres=# SELECT pg_walfile_name('0/2000138');
     pg_walfile_name      
--------------------------
 000000010000000000000002
(1 row)
  • ベースバックアップ終了後のWAL書き込み先
postgres=# SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn 
---------------------------
 0/3000148
(1 row)

postgres=# SELECT pg_walfile_name(pg_current_wal_insert_lsn());
     pg_walfile_name      
--------------------------
 000000010000000000000003
(1 row)
  • 以降は3に書かれていく

backup_labelとバックアップ履歴ファイルの内容

  • backup_labelファイル

    • pg_start_backup()実行後、pg_stop_backup()実行前までデータベースクラスタに存在
postgres=# SELECT pg_start_backup('test');
 pg_start_backup 
-----------------
 0/4000028
(1 row)
cat backup_label
START WAL LOCATION: 0/4000028 (file 000000010000000000000004)
CHECKPOINT LOCATION: 0/4000060
BACKUP METHOD: pg_start_backup
BACKUP FROM: master
START TIME: 2020-02-14 14:59:49 UTC
LABEL: test
START TIMELINE: 1
postgres=# 
  • バックアップ履歴ファイル

    • STOP WAL LOCATIONSTOP TIMEが追加される

Column: 並行したバックアップ取得の制御

  • 第三引数falseで並行実行

    • 並行でない排他実行はdeprecated
postgres=# SELECT pg_start_backup('test_exclusive', false, false);
 pg_start_backup 
-----------------
 0/8000060
(1 row)
  • データベースクラスタをcpやらtarやらでバックアップしてベースバックアップを取得
  • のち、pg_stop_backup(false)する
postgres=# SELECT * from pg_stop_backup(false);
NOTICE:  all required WAL segments have been archived
    lsn    |                           labelfile                           | spcmapfile 
-----------+---------------------------------------------------------------+------------
 0/6000138 | START WAL LOCATION: 0/6000060 (file 000000010000000000000006)+| 
           | CHECKPOINT LOCATION: 0/6000098                               +| 
           | BACKUP METHOD: streamed                                      +| 
           | BACKUP FROM: master                                          +| 
           | START TIME: 2020-02-14 15:03:37 UTC                          +| 
           | LABEL: test_exclusive                                        +| 
           | START TIMELINE: 1                                            +| 
           |                                                               | 
(1 row)
  • この内容をベースバックアップに含める

    • labelfileの内容: backup_labelファイル
    • spcmapfileの内容: tablespace_mapファイル

WALのアーカイブの流れ

  • *.readyなやつがアーカイバプロセスによりarchive_commandによりアーカイブされる

    • *.doneにリネームされる
postgres=# \! ls -lAR pg_wal/
pg_wal/:
total 49160
-rw------- 1 postgres postgres 16777216 Feb 14 15:03 000000010000000000000006
-rw------- 1 postgres postgres      326 Feb 14 15:03 000000010000000000000006.00000060.backup
-rw------- 1 postgres postgres 16777216 Feb 14 15:03 000000010000000000000007
-rw------- 1 postgres postgres 16777216 Feb 14 15:03 000000010000000000000008
drwx------ 2 postgres postgres     4096 Feb 14 15:03 archive_status

pg_wal/archive_status:
total 0
-rw------- 1 postgres postgres 0 Feb 14 15:03 000000010000000000000006.00000060.backup.done
-rw------- 1 postgres postgres 0 Feb 14 15:03 000000010000000000000006.done
  • psコマンドでアーカイバプロセスを確認すると、最後にアーカイブしたWALセグメントを確認できる
postgres-# \! ps axfww | grep postgres
   67 pts/1    Ss+    0:00 /usr/lib/postgresql/12/bin/psql
 1094 pts/1    S+     0:00  \_ sh -c ps axfww | grep postgres
 1096 pts/1    S+     0:00      \_ grep postgres
    1 ?        Ss     0:00 postgres
   27 ?        Ss     0:00 postgres: checkpointer   
   28 ?        Ss     0:00 postgres: background writer   
   29 ?        Ss     0:00 postgres: walwriter   
   30 ?        Ss     0:00 postgres: autovacuum launcher   
   31 ?        Ss     0:00 postgres: archiver   last was 000000010000000000000006.00000060.backup
   32 ?        Ss     0:00 postgres: stats collector   
   33 ?        Ss     0:00 postgres: logical replication launcher   
   87 ?        Ss     0:00 postgres: postgres postgres [local] idle
  • 詳細情報
postgres=# SELECT * FROM pg_stat_archiver;
-[ RECORD 1 ]------+-----------------------------------------
archived_count     | 9
last_archived_wal  | 000000010000000000000006.00000060.backup
last_archived_time | 2020-02-14 15:03:43.471038+00
failed_count       | 9
last_failed_wal    | 000000010000000000000001
last_failed_time   | 2020-02-14 14:54:40.047857+00
stats_reset        | 2020-02-14 14:49:42.366489+00
  • failed : archive先ディレクトリを掘り忘れて失敗してたやつ
cp: cannot create regular file '/tmp/archive/': Not a directory
2020-02-14 14:54:40.047 UTC [31] LOG:  archive command failed with exit code 1
2020-02-14 14:54:40.047 UTC [31] DETAIL:  The failed archive command was: cp pg_wal/000000010000000000000001 /tmp/archive/
2020-02-14 14:54:40.047 UTC [31] WARNING:  archiving write-ahead log file "000000010000000000000001" failed too many times, will try again later