PostgreSQLのWAL周りについて調べる機会がありメモ。
pg_waldump
PostgreSQLでは、WALレコードをダンプするpg_waldumpというツールが用意されています。pg_waldumpはコマンドラインツールで、引数にWALセグメントファイルを指定することで、対象のセグメントのレコードを画面にダーっと出力してくれます。WALの内部を知りたい場合、pg_waldumpは大変便利です。
例えば、こんな感じで使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ psql -d postgres psql (12beta3) Type "help" for help. postgres=# select * from pg_ls_waldir() limit 1; name | size | modification --------------------------+----------+------------------------ 000000010000000000000004 | 16777216 | 2019-09-15 11:59:30+09 (1 row) postgres=# \! pg_waldump pg_wal/000000010000000000000004; rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000028, prev 0/03000110, desc: RUNNING_XACTS nextXid 488 latestCompletedXid 487 oldestRunningXid 488 rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000060, prev 0/04000028, desc: RUNNING_XACTS nextXid 488 latestCompletedXid 487 oldestRunningXid 488 rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn: 0/04000098, prev 0/04000060, desc: CHECKPOINT_ONLINE redo 0/4000028; tli 1; prev tli 1; fpw true; xid 0:488; oid 24576; multi 1; offset 0; oldest xid 479 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 488; online rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000110, prev 0/04000098, desc: RUNNING_XACTS nextXid 488 latestCompletedXid 487 oldestRunningXid 488 rmgr: Heap len (rec/tot): 54/ 150, tx: 488, lsn: 0/04000148, prev 0/04000110, desc: INSERT off 2 flags 0x00, blkref #0: rel 1663/12937/16384 blk 0 FPW rmgr: Transaction len (rec/tot): 34/ 34, tx: 488, lsn: 0/040001E0, prev 0/04000148, desc: COMMIT 2019-09-15 11:56:40.963685 JST rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000208, prev 0/040001E0, desc: RUNNING_XACTS nextXid 489 latestCompletedXid 488 oldestRunningXid 489 rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn: 0/04000240, prev 0/04000208, desc: CHECKPOINT_SHUTDOWN redo 0/4000240; tli 1; prev tli 1; fpw true; xid 0:489; oid 24576; multi 1; offset 0; oldest xid 479 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 0; shutdown rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/040002B8, prev 0/04000240, desc: RUNNING_XACTS nextXid 489 latestCompletedXid 488 oldestRunningXid 489 rmgr: XLOG len (rec/tot): 24/ 24, tx: 0, lsn: 0/040002F0, prev 0/040002B8, desc: SWITCH |
pg_waldumpが出力する内容は以下の通りです。
rmgr | リソースマネージャの種別です。PostgreSQLでは、レコード種別ごとにレコードを処理する関数が用意されており、レコード種別で呼び分けられるようになっています。https://doxygen.postgresql.org/rmgrlist_8h_source.html |
len (rec/tot) | Full-page image (FPI)を除いた長さとレコード全体長さ |
tx | トランザクションID |
lsn | 現在読み取ったレコードのLSN |
prev | 1つ前のレコードのLSN |
desc | リソースマネージャが出力するWALレコードに関する情報 |
他にもトランザクションIDを指定したり、WALの開始や終了位置を指定してダンプすることも可能です。
出力はテキスト形式ですので、コマンドラインで加工したりすることもできます。pg_waldumpを触っている中、ふとSQLでも操作できたら良いなと思い、walの読み取り方法や拡張機能の作り方の学習もかねて、walをSQLで出力できるツールwalreaderを作ってみました。この拡張機能は、あくまで学習用です。あまり慣れていないのでバグがあるかもしれません(きっと)。。
walreader
使い方は簡単です。以下で拡張機能をインストールします。
1 2 3 |
$ git clone https://github.com/moritetu/walreader.git $ cd walreader $ make USE_PGXS=1 install |
続いて、拡張機能を有効化して、SELECT文を実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
postgres=# CREATE EXTENSION walreader; CREATE EXTENSION postgres=# \x Expanded display is on. postgres=# select * from read_wal_segment('000000010000000000000016') limit 3; WARNING: invalid record length at 0/161D5D18: wanted 24, got 0 -[ RECORD 1 ]------------------------------------------------------ timeline | 1 walseg | 000000010000000000000016 seg_off | 40 page | 1 page_off | 40 rmgr | Standby rec_len | 50 tot_len | 50 tot_rlen | 56 tx | 0 lsn | 0/16000028 end_lsn | 0/1600005F prev_lsn | 0/1501A5B0 identify | RUNNING_XACTS rmgr_desc | nextXid 649 latestCompletedXid 648 oldestRunningXid 649 -[ RECORD 2 ]------------------------------------------------------ timeline | 1 walseg | 000000010000000000000016 seg_off | 96 page | 1 page_off | 96 rmgr | Heap rec_len | 163 tot_len | 163 tot_rlen | 168 tx | 649 lsn | 0/16000060 end_lsn | 0/16000107 prev_lsn | 0/16000028 identify | INSERT+INIT rmgr_desc | off 1 flags 0x00 -[ RECORD 3 ]------------------------------------------------------ timeline | 1 walseg | 000000010000000000000016 seg_off | 264 page | 1 page_off | 264 rmgr | Transaction rec_len | 34 tot_len | 34 tot_rlen | 40 tx | 649 lsn | 0/16000108 end_lsn | 0/1600012F prev_lsn | 0/16000060 identify | COMMIT rmgr_desc | 2019-09-29 01:42:47.230124+09 postgres=# select rec.* from (select name from pg_ls_waldir()) w, lateral read_wal_segment(w.name) rec; -- walディレクトリ下のwalファイルを読む |
pg_waldumpと少し出力が異なります。出力内容は以下です。
timeline | タイムラインID |
walseg | walファイル名 |
seg_off | walファイル内での先頭からのオフセット |
page | ページNo |
page_off | ページ内の先頭からのオフセット |
rmgr | リソースマネージャ種別 |
rec_len | Full-page image (FPI)を除いたレコード長 |
tot_len | トータルレコード長 |
tot_rlen | アライメントされたトータルレコード長 |
tx | トランザクションID |
lsn | レコードの開始LSN |
end_lsn | レコードの終了LSN |
prev_lsn | 1つ前のレコードの開始LSN |
identify | リソースマネージャでの操作識別子 |
rmgr_desc | リソースマネージャが出力するWALレコードに関する情報 |
GitHub - moritetu/walreader: a postgresql extension to read wal with sql functions
a postgresql extension to read wal with sql functions - moritetu/walreader
出力したいwalの範囲指定も想定していますが、タイムラインなどの切り替えは考慮されていないです。
WALの構造
walの中身は以下のような感じになっているようです。
コメント