PostgreSQL利用日志文件来防止断电之类的故障导致的数据丢失,任何试图修改数据库的操作都会写一份日志记录到磁盘,这个日志称为XLOG/WAL。在数据库定位问题时,就可以使用pg_xlogdump/pg_waldump来解析XLOG/WAL日志,包括日志类型、对应的事务号、修改的文件等等。
pg_xlogdump/pg_waldump是查不出数据的,要查出数据,首先要有数据结构,然后要有数据。
数据结构是需要查数据库的元数据才能查到,pg_xlogdump没办法做到。PostgreSQL基于XLOG的恢复并不是逻辑恢复,而是物理块的恢复。所以不需要解读数据。
language
pg_waldump decodes and displays PostgreSQL write-ahead logs for debugging.
Usage:
pg_waldump [OPTION]... [STARTSEG [ENDSEG]]
Options:
-b, --bkp-details output detailed information about backup blocks
-B, --block=N with --relation, only show records that modify block N
-e, --end=RECPTR stop reading at WAL location RECPTR
-f, --follow keep retrying after reaching end of WAL
-F, --fork=FORK only show records that modify blocks in fork FORK;
valid names are main, fsm, vm, init
-n, --limit=N number of records to display
-p, --path=PATH directory in which to find WAL segment files or a
directory with a ./pg_wal that contains such files
(default: current directory, ./pg_wal, $PGDATA/pg_wal)
-q, --quiet do not print any output, except for errors
-r, --rmgr=RMGR only show records generated by resource manager RMGR;
use --rmgr=list to list valid resource manager names
-R, --relation=T/D/R only show records that modify blocks in relation T/D/R
-s, --start=RECPTR start reading at WAL location RECPTR
-t, --timeline=TLI timeline from which to read WAL records
(default: 1 or the value used in STARTSEG)
-V, --version output version information, then exit
-w, --fullpage only show records with a full page write
-x, --xid=XID only show records with transaction ID XID
-z, --stats[=record] show statistics instead of records
(optionally, show per-record statistics)
--save-fullpage=DIR save full page images to DIR
-?, --help show this help, then exit
Report bugs to <pgsql-bugs@lists.postgresql.org>.
PostgreSQL home page: <https://www.postgresql.org/>
中文解释:
-b, --bkp-details 输出有关备份块的细节。
-B, --block=N ,带上--relation仅显示修改块N的记录
-e, --end=RECPTR 在指定的日志位置停止读取,而不是一直读取到日志流的末尾。
-f, --follow 在到达可用 WAL 的末尾之后,保持每秒轮询一次是否有新的 WAL 出现。
-F, --fork=FORK 只显示fork fork中修改块的记录;有效名称为main、fsm、vm、init
-n, --limit=N 显示指定数量的记录,然后停止。
-p, --path=PATH 要在哪个目录中寻找日志段文件。默认是在当前目录的pg_xlog 子目录中搜索。
-r, --rmgr=RMGR 只显示由指定资源管理器生成的记录。如果把list作为资源管理器名称 传递给这个选项,则打印出可用资源管理器名称的列表然后退出。
-R, --relation=T/D/R 仅显示修改T/D/R关系中的块的记录
-s, --start=RECPTR 要从哪个日志位置开始读取。默认是从找到的最早的文件的第一个可用日志记录开始。
-t, --timeline=TLI 要从哪个时间线读取日志记录。默认是使用startseg(如果指定) 中的值,否则默认为 1
-V, --version 打印pg_xlogdump版本并且退出。
-w, --fullpage 只显示full page write写入的记录
-x, --xid=XID 只显示用给定事务 ID 标记的记录。
-z, --stats[=record] 显示概括统计信息(记录的数量和尺寸以及全页镜像)而不是显示 每个记录。可以选择针对每个记录生成统计信息,而不是针对每个 资源管理器生成。
--save-fullpage=DIR 将full page image保存到DIR
一、常规用法
1.根据txid定位xlog里的相关记录
当每个新记录被写入时,WAL记录被追加到WAL日志中。 插入位置由日志序列号(LSN)描述,该日志序列号是日志中的字节偏移量, 随每个新记录单调递增。而txid表示事物id,一个txid可以对应多个lsn,insert操作会记录一次lsn号,commit操作会记录一次lsn号,即每次操作记录都会生成lsn。
postgres=# select xmin,xmax,ctid,* from text_waldump;
xmin | xmax | ctid | id | name | times
------+------+-------+----+------+----------------------------
1016 | 0 | (0,1) | 1 | ysl | 2023-12-18 10:32:52.054172
1019 | 0 | (0,4) | 2 | ysl2 | 2023-12-18 10:33:01.112948
(2 rows)
postgres=# select pg_relation_filenode('text_waldump');
pg_relation_filenode
----------------------
57978
(1 row)
postgres@ubuntu-linux-22-04-desktop:~/data-16beta1/pg_wal$ pg_waldump 000000010000000000000004 -x 1019
rmgr: Heap len (rec/tot): 71/ 71, tx: 1019, lsn: 0/04FD80D8, prev 0/04FD80A0, desc: HOT_UPDATE old_xmax: 1019, old_off: 2, old_infobits: [], flags: 0x60, new_xmax: 0, new_off: 4, blkref #0: rel 1663/5/57978 blk 0
rmgr: Transaction len (rec/tot): 34/ 34, tx: 1019, lsn: 0/04FD8120, prev 0/04FD80D8, desc: COMMIT 2023-12-18 10:33:37.837373 CST
pg_waldump: error: error in WAL record at 0/4FD83D8: invalid record length at 0/4FD8410: expected at least 24, got 0
如下是解析内容的部分解释:
rmgr : Heap
内部将WAL日志归类到20多种不同的资源管理器,使用pg_waldump --rmgr=list可以查看支持的类型:XLOG, Transaction, Storage, CLOG, Database, Tablespace, MultiXact, RelMap, Standby, Heap2, Heap, Btree, Hash, Gin, Gist, Sequence, SPGist, BRIN, CommitTs, ReplicationOrigin, Generic, LogicalMessage
len (rec/tot): 71/ 71 :
WAL记录的总长度是71字节,其中main data部分是71字节
tx: 1019
事物id
lsn: 0/04FD80D8
本WAL记录的LSN
prev 0/04FD80D8
上条WAL记录的LSN
desc: HOT_UPDATE
这条记录的类型:HOT更新 (HOT update) 一个UPDATE,其中新的元组成为仅堆元组,并且不创建新的索引条目。
old_xmax:1019
记录update旧元组的xmax,redo时用以填充元组头数据
old_off: 2
记录旧元组在其page中的相对位置
old_infobits: []
记录旧元组的t_infomask和t_infomask2的值,redo时用以填充元组头数据
flags: 0x60
标志位
new_xmax: 0
记录新元组的xmax
new_off: 4
记录新元组在其page中的相对位置
blkref #0: rel 1663/5/57978 blk 0
引用的第一个page所属的对表文件为1663/5/57978,块号为0(即ctid的前半部分)
2.获取xlog里的记录的统计信息
命令加 -z
language
postgres@ubuntu-linux-22-04-desktop:~/data-16beta1/pg_wal$ pg_waldump 000000010000000000000004 -z
WAL statistics between 0/4000028 and 0/4FD8410:
Type N (%) Record size (%) FPI size (%) Combined size (%)
---- - --- ----------- --- -------- --- ------------- ---
XLOG 1953 ( 2.86) 100233 ( 2.02) 8546456 ( 74.66) 8646689 ( 52.66)
Transaction 133 ( 0.19) 74913 ( 1.51) 0 ( 0.00) 74913 ( 0.46)
Storage 631 ( 0.92) 26502 ( 0.53) 0 ( 0.00) 26502 ( 0.16)
CLOG 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
Database 3 ( 0.00) 106 ( 0.00) 0 ( 0.00) 106 ( 0.00)
Tablespace 6 ( 0.01) 208 ( 0.00) 0 ( 0.00) 208 ( 0.00)
MultiXact 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
RelMap 2 ( 0.00) 1130 ( 0.02) 0 ( 0.00) 1130 ( 0.01)
Standby 321 ( 0.47) 15638 ( 0.31) 0 ( 0.00) 15638 ( 0.10)
Heap2 730 ( 1.07) 131215 ( 2.64) 313228 ( 2.74) 444443 ( 2.71)
Heap 61623 ( 90.14) 4413499 ( 88.76) 1102820 ( 9.63) 5516319 ( 33.60)
Btree 2964 ( 4.34) 208841 ( 4.20) 1484564 ( 12.97) 1693405 ( 10.31)
Hash 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
Gin 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
Gist 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
Sequence 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
SPGist 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
BRIN 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
CommitTs 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
ReplicationOrigin 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
Generic 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
LogicalMessage 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00)
-------- -------- -------- --------
Total 68366 4972285 [30.28%] 11447068 [69.72%] 16419353 [100%]
pg_waldump: error: error in WAL record at 0/4FD83D8: invalid record length at 0/4FD8410: expected at least 24, got 0
命令加行--stats=record
language
postgres@ubuntu-linux-22-04-desktop:~/data-16beta1/pg_wal$ pg_waldump 000000010000000000000004 --stats=record
WAL statistics between 0/4000028 and 0/4FD8410:
Type N (%) Record size (%) FPI size (%) Combined size (%)
---- - --- ----------- --- -------- --- ------------- ---
XLOG/CHECKPOINT_SHUTDOWN 26 ( 0.04) 2964 ( 0.06) 0 ( 0.00) 2964 ( 0.02)
XLOG/CHECKPOINT_ONLINE 47 ( 0.07) 5358 ( 0.11) 0 ( 0.00) 5358 ( 0.03)
XLOG/NEXTOID 11 ( 0.02) 330 ( 0.01) 0 ( 0.00) 330 ( 0.00)
XLOG/FPI 1869 ( 2.73) 91581 ( 1.84) 8546456 ( 74.66) 8638037 ( 52.61)
Transaction/COMMIT 103 ( 0.15) 73889 ( 1.49) 0 ( 0.00) 73889 ( 0.45)
Transaction/ABORT 30 ( 0.04) 1024 ( 0.02) 0 ( 0.00) 1024 ( 0.01)
Storage/CREATE 631 ( 0.92) 26502 ( 0.53) 0 ( 0.00) 26502 ( 0.16)
Database/CREATE_WAL_LOG 2 ( 0.00) 68 ( 0.00) 0 ( 0.00) 68 ( 0.00)
Database/DROP 1 ( 0.00) 38 ( 0.00) 0 ( 0.00) 38 ( 0.00)
Tablespace/CREATE 4 ( 0.01) 148 ( 0.00) 0 ( 0.00) 148 ( 0.00)
Tablespace/DROP 2 ( 0.00) 60 ( 0.00) 0 ( 0.00) 60 ( 0.00)
RelMap/UPDATE 2 ( 0.00) 1130 ( 0.02) 0 ( 0.00) 1130 ( 0.01)
Standby/LOCK 85 ( 0.12) 3582 ( 0.07) 0 ( 0.00) 3582 ( 0.02)
Standby/RUNNING_XACTS 231 ( 0.34) 11606 ( 0.23) 0 ( 0.00) 11606 ( 0.07)
Standby/INVALIDATIONS 5 ( 0.01) 450 ( 0.01) 0 ( 0.00) 450 ( 0.00)
Heap2/PRUNE 84 ( 0.12) 5960 ( 0.12) 101844 ( 0.89) 107804 ( 0.66)
Heap2/VISIBLE 275 ( 0.40) 16250 ( 0.33) 40960 ( 0.36) 57210 ( 0.35)
Heap2/MULTI_INSERT 355 ( 0.52) 86376 ( 1.74) 170424 ( 1.49) 256800 ( 1.56)
Heap2/MULTI_INSERT+INIT 16 ( 0.02) 22629 ( 0.46) 0 ( 0.00) 22629 ( 0.14)
Heap/INSERT 60029 ( 87.81) 4280871 ( 86.09) 455304 ( 3.98) 4736175 ( 28.85)
Heap/DELETE 957 ( 1.40) 51993 ( 1.05) 322344 ( 2.82) 374337 ( 2.28)
Heap/UPDATE 51 ( 0.07) 12277 ( 0.25) 95116 ( 0.83) 107393 ( 0.65)
Heap/HOT_UPDATE 145 ( 0.21) 15107 ( 0.30) 67440 ( 0.59) 82547 ( 0.50)
Heap/LOCK 47 ( 0.07) 2573 ( 0.05) 56736 ( 0.50) 59309 ( 0.36)
Heap/INPLACE 39 ( 0.06) 5442 ( 0.11) 105880 ( 0.92) 111322 ( 0.68)
Heap/INSERT+INIT 353 ( 0.52) 43734 ( 0.88) 0 ( 0.00) 43734 ( 0.27)
Heap/UPDATE+INIT 2 ( 0.00) 1502 ( 0.03) 0 ( 0.00) 1502 ( 0.01)
Btree/INSERT_LEAF 2927 ( 4.28) 201356 ( 4.05) 1481200 ( 12.94) 1682556 ( 10.25)
Btree/INSERT_UPPER 6 ( 0.01) 366 ( 0.01) 2212 ( 0.02) 2578 ( 0.02)
Btree/SPLIT_R 6 ( 0.01) 4648 ( 0.09) 0 ( 0.00) 4648 ( 0.03)
Btree/INSERT_POST 3 ( 0.00) 185 ( 0.00) 1152 ( 0.01) 1337 ( 0.01)
Btree/DEDUP 1 ( 0.00) 208 ( 0.00) 0 ( 0.00) 208 ( 0.00)
Btree/DELETE 8 ( 0.01) 908 ( 0.02) 0 ( 0.00) 908 ( 0.01)
Btree/NEWROOT 13 ( 0.02) 1170 ( 0.02) 0 ( 0.00) 1170 ( 0.01)
-------- -------- -------- --------
Total 68366 4972285 [30.28%] 11447068 [69.72%] 16419353 [100%]
pg_waldump: error: error in WAL record at 0/4FD83D8: invalid record length at 0/4FD8410: expected at least 24, got 0
各个列的解释:
Type:xlog中的日志类型
N: 次数及占比
Record size:记录的大小及占比
FPI size: full page image大小及占比
combined size: 记录和FPI的大小总和
开启了full_page_writes会导致wal中的FPI占比大
3.指定开始和结束的lsn
-s和-e分别指定wal里开始和结束的lsn
language
postgres@ubuntu-linux-22-04-desktop:~/data-16beta1/pg_wal$ pg_waldump -s 0/4000028 -e 0/4000185
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000028, prev 0/03000100, desc: RUNNING_XACTS nextXid 887 latestCompletedXid 886 oldestRunningXid 887
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000060, prev 0/04000028, desc: RUNNING_XACTS nextXid 887 latestCompletedXid 886 oldestRunningXid 887
rmgr: XLOG len (rec/tot): 114/ 114, tx: 0, lsn: 0/04000098, prev 0/04000060, desc: CHECKPOINT_ONLINE redo 0/4000060; tli 1; prev tli 1; fpw true; xid 0:887; oid 41399; multi 1; offset 0; oldest xid 722 in DB 24587; oldest multi 1 in DB 5; oldest/newest commit timestamp xid: 0/0; oldest running xid 887; online
rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/04000110, prev 0/04000098, desc: RUNNING_XACTS nextXid 887 latestCompletedXid 886 oldestRunningXid 887
4.根据数据库对象查询xlog的记录
使用 --relation=关键字或者-R,后边跟的格式应该是"tablespace OID/database OID/relation filenode",否则会报错。
language
postgres=# select oid from pg_tablespace where spcname='pg_default';
oid
------
1663
(1 row)
postgres=# select oid from pg_database where datname='postgres';
oid
-----
5
(1 row)
postgres=# select pg_relation_filenode('text_waldump');
pg_relation_filenode
----------------------
57978
(1 row)
postgres@ubuntu-linux-22-04-desktop:~/data-16beta1/pg_wal$ pg_waldump 000000010000000000000004 -R 1663/5/57978
rmgr: Heap len (rec/tot): 71/ 71, tx: 1016, lsn: 0/04FD7EB8, prev 0/04FD7E80, desc: INSERT+INIT off: 1, flags: 0x00, blkref #0: rel 1663/5/57978 blk 0
rmgr: Heap len (rec/tot): 79/ 79, tx: 1017, lsn: 0/04FD7F60, prev 0/04FD7F28, desc: INSERT off: 2, flags: 0x00, blkref #0: rel 1663/5/57978 blk 0
rmgr: Heap len (rec/tot): 79/ 79, tx: 1018, lsn: 0/04FD8028, prev 0/04FD7FD8, desc: INSERT off: 3, flags: 0x00, blkref #0: rel 1663/5/57978 blk 0
rmgr: Heap len (rec/tot): 71/ 71, tx: 1019, lsn: 0/04FD80D8, prev 0/04FD80A0, desc: HOT_UPDATE old_xmax: 1019, old_off: 2, old_infobits: [], flags: 0x60, new_xmax: 0, new_off: 4, blkref #0: rel 1663/5/57978 blk 0
rmgr: Heap len (rec/tot): 54/ 54, tx: 1020, lsn: 0/04FD8148, prev 0/04FD8120, desc: DELETE xmax: 1020, off: 3, infobits: [KEYS_UPDATED], flags: 0x00, blkref #0: rel 1663/5/57978 blk 0
pg_waldump: error: error in WAL record at 0/4FD83D8: invalid record length at 0/4FD8410: expected at least 24, got 0