PostgreSQL WALの中身を表示する

PostgreSQLのWAL周りについて調べる機会がありメモ。

pg_waldump

PostgreSQLでは、WALレコードをダンプするpg_waldumpというツールが用意されています。pg_waldumpはコマンドラインツールで、引数にWALセグメントファイルを指定することで、対象のセグメントのレコードを画面にダーっと出力してくれます。WALの内部を知りたい場合、pg_waldumpは大変便利です。

例えば、こんな感じで使えます。

$ 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

使い方は簡単です。以下で拡張機能をインストールします。

$ git clone https://github.com/moritetu/walreader.git
$ cd walreader
$ make USE_PGXS=1 install

続いて、拡張機能を有効化して、SELECT文を実行します。

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レコードに関する情報

https://github.com/moritetu/walreader

出力したいwalの範囲指定も想定していますが、タイムラインなどの切り替えは考慮されていないです。

WALの構造

walの中身は以下のような感じになっているようです。

wal structure

参考リンク

byebyehaikikyou

日記やIT系関連のネタ、WordPressに関することなど様々な事柄を書き付けた雑記です。ITエンジニア経験があるのでプログラミングに関することなどが多いです。

シェアする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする

Translate »