pg_walex最小,最强,最快,最易上手的 PostgreSQL WAL 日志解析工具,用起来就德芙一样丝滑

举报
yd_74227107 发表于 2026/10/27 19:19:12 2026/10/27
【摘要】 pg_walex让你:能读 、 能还原、 能后悔 、 能实时 让你的 DROP 不再是终点,TRUNCATE 不再靠祈祷——WAL 还在,就还有得救。

回滚能力让pg_walex成为真的后悔药

最小,最强,最快,最易上手的 PostgreSQL WAL 日志解析工具,用起来就德芙一样丝滑

pg_walex 1.1.0,把 PostgreSQL 的 WAL 从"只读的黑匣子"变成了"可逆的时间机器"。

版本更新预览

  • 输出增加了操作类型 type,lsn, timestamp
  • --rollback + GET/POST /api/v1/rollback 正向语句后面紧跟逆操作,可回放撤销
  • 增强对 truncate 和 drop 的回滚能力
  • 修复在低版本C编译器编译时strncopy告警的问题的问题
  • 使用memcopy替代strncopy
  • 实时监控 + GET /api/v1/item

一、主要增加功能

  • --rollback 支持数据回滚能力
  • RESTful API 回滚能力,可接入多个平台

二、源码下载地址

源码可从github gitee gitcode 下载

●●●Bash
git clone https://github.com/shaohuasong-fang/pg_walex.git
git clone https://gitee.com/developerhonor/pg_walex.git
git clone https://gitcode.com/sungsasong/pg_walex.git

三、编译安装

3.1 编译构建

●●●Bash
# make -j$(nproc)
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_util.o src/pwe_util.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_version.o src/pwe_version.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_wal.o src/pwe_wal.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_tuple.o src/pwe_tuple.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_catalog.o src/pwe_catalog.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_recon.o src/pwe_recon.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_output.o src/pwe_output.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_main.o src/pwe_main.c
cc -O2 -g -std=c11 -Wall -Wextra -Wno-unused-parameter -pthread -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE -Iinclude -Isrc -c -o src/pwe_http.o src/pwe_http.c
cc  -o pg_walex src/pwe_util.o src/pwe_version.o src/pwe_wal.o src/pwe_tuple.o src/pwe_catalog.o src/pwe_recon.o src/pwe_output.o src/pwe_main.o src/pwe_http.o -pthread

3.2 安装

●●●Bash
# make install PREFIX=/usr/local
install -d /usr/local/bin
install -m 0755 pg_walex /usr/local/bin/pg_walex

3.3 查看版本

●●●Bash
# pg_walex --version
pg_walex 1.1.0

四、验证基本的DML回滚功能

4.1 建库

●●●SQL
# psql -U postgres -d postgres -p6432
psql (18.4)
Type "help" for help.

postgres=# create database db_rollback;
CREATE DATABASE

4.2 确保wal_level = logical

●●●SQL
db_rollback=# show wal_level ;
 wal_level 
-----------
 logical
(1 row)

4.3 查看LSN和对应的文件

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB47AF10
(1 row)

4.4 模拟数据表

●●●SQL
db_rollback=# CREATE TABLE tab_rollback(id int primary key,name varchar(20));
CREATE TABLE
db_rollback=# INSERT INTO tab_rollback VALUES(1,'Verifying rollback');
INSERT 0 1

4.5 再次查看LSN和对应的文件

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB47DAC8
(1 row)

4.6 模拟误删除数据

●●●SQL
db_rollback=# DELETE FROM tab_rollback WHERE id = 1;
DELETE 1

4.7 查看日志LSN和对应的文件

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB47DB38
(1 row)

4.8 找误删除的数据

这里通过起始LSN 5/BB47DAC8 和结束LSN 5/BB47DB38的区间找

●●●SQL
[root@PGServer ~]# pg_walex -f /data/tmp/data/pg_wal/0000000100000005000000BB --rollback -s 5/BB47DAC8 -e 5/BB47DB38
\connect db_rollback
-- pg_walex: type=delete,xid=1233,lsn=5/BB47DAC8,timestamp=2026-10-27 08:02:10.117709+00
BEGIN;
DELETE FROM public.tab_rollback WHERE id IS NOT DISTINCT FROM 1;
-- pg_walex: rollback,xid=1233,lsn=5/BB47DAC8,timestamp=2026-10-27 08:02:10.117709+00
INSERT INTO public.tab_rollback (id, name) VALUES (1, 'Verifying rollback');
COMMIT;

五、验证DROP和TRUNCATE的回滚能力

说明: 注意删除操作和TRUNCATE的恢复受限于缓存大小,如果误删除数据,请尽快停止写入数据库

5.1 验证DROP回滚能力

5.1.1 查看LSN及文件位置

●●●PL/pgSQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB47DC78
(1 row)

5.1.2 模拟表及插入5条数据

●●●SQL
db_rollback=# CREATE TABLE tab_drop(id int primary key,name varchar(20));
CREATE TABLE
db_rollback=# INSERT INTO tab_drop VALUES(1,'first');
INSERT 0 1
db_rollback=# INSERT INTO tab_drop VALUES(2,'second');
INSERT 0 1
db_rollback=# INSERT INTO tab_drop VALUES(3,'third');
INSERT 0 1
db_rollback=# INSERT INTO tab_drop VALUES(4,'forth');
INSERT 0 1
db_rollback=# INSERT INTO tab_drop VALUES(5,'fifth');
INSERT 0 1

5.1.3 执行删除表操作

●●●SQL
-- 删除前的日志序列号,用作DROP 操作的起始 LSN
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB4A89A0
(1 row)

db_rollback=# DROP TABLE tab_drop ;
DROP TABLE

5.1.4 查看LSN及文件位置

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB4ACB68
(1 row)

5.1.5 WAL 回滚 DROP 的能力

●●●SQL
[root@PGServer ~]# pg_walex -f /data/tmp/data/pg_wal/0000000100000005000000BB --rollback -s 5/BB4A89A0 -e 5/BB4ACB68
\connect db_rollback
-- pg_walex: type=drop,xid=1240,lsn=5/BB4ABB08,timestamp=2026-10-27 08:11:09.278194+00
BEGIN;
DROP TABLE public.tab_drop;
-- pg_walex: rollback,xid=1240,lsn=5/BB4AC640,timestamp=2026-10-27 08:11:09.278194+00
CREATE TABLE public.tab_drop (
  id int4 NOT NULL,
  name varchar(20),
  PRIMARY KEY (id)
);
INSERT INTO public.tab_drop (id, name) VALUES (3, 'third');
INSERT INTO public.tab_drop (id, name) VALUES (2, 'second');
INSERT INTO public.tab_drop (id, name) VALUES (1, 'first');
INSERT INTO public.tab_drop (id, name) VALUES (5, 'fifth');
INSERT INTO public.tab_drop (id, name) VALUES (4, 'forth');
COMMIT;

5.2 验证 TRUNCATE 回滚能力

5.2.1 模拟数据

●●●SQL
db_rollback=# CREATE TABLE tab_truncate(id int primary key,name varchar(20));
CREATE TABLE
db_rollback=# INSERT INTO tab_truncate (id, name) VALUES
    (1, 'Alice'),
    (2, 'Bob'),
    (3, 'Charlie'),
    (4, 'Diana'),
    (5, 'Eve');
INSERT 0 5

5.2.2 查看LSN及文件位置

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB4D55D0
(1 row)

####5.2.3 清空数据

●●●SQL
db_rollback=# truncate table tab_truncate ;
TRUNCATE TABLE

5.2.4 查看LSN及文件位置

●●●SQL
db_rollback=# SELECT pg_walfile_name(pg_current_wal_lsn()),pg_current_wal_lsn();
     pg_walfile_name      | pg_current_wal_lsn 
--------------------------+--------------------
 0000000100000005000000BB | 5/BB4D9E30
(1 row)

5.2.5 TRUNCATE 回滚能力验证

●●●SQL
[root@PGServer ~]# pg_walex -f /data/tmp/data/pg_wal/0000000100000005000000BB --rollback -s 5/BB4D55D0 -e 5/BB4D9E30
\connect db_rollback
-- pg_walex: type=truncate,xid=1243,lsn=5/BB4D9AA8,timestamp=2026-10-27 08:18:03.800537+00
BEGIN;
TRUNCATE TABLE public.tab_truncate;
-- pg_walex: rollback,xid=1243,lsn=5/BB4D9CF8,timestamp=2026-10-27 08:18:03.800537+00
INSERT INTO public.tab_truncate (id, name) VALUES (3, 'Charlie');
INSERT INTO public.tab_truncate (id, name) VALUES (2, 'Bob');
INSERT INTO public.tab_truncate (id, name) VALUES (1, 'Alice');
INSERT INTO public.tab_truncate (id, name) VALUES (5, 'Eve');
INSERT INTO public.tab_truncate (id, name) VALUES (4, 'Diana');
COMMIT;

综上: 对于DROP和TRUNCATE的表,也可以通过WAL日志找回来。

六. RESTful API 支持

6.1 启动

●●●SQL
[root@PGServer ~]# pg_walex --serve --monitor --listen 0.0.0.0 --port 8900 \
  --token my-secret-token --dir  /data/tmp/data/pg_wal
pg_walex 1.1.0 REST API listening on http://0.0.0.0:8900/api/v1
pg_walex: default WAL directory: /data/tmp/data/pg_wal
pg_walex: monitoring /data/tmp/data/pg_wal; latest statement at /api/v1/item

6.2 验证从指定LSN开始的监控

●●●SQL
[root@PGServer ~]# curl -s -H "Authorization: Bearer my-secret-token"   'http://127.0.0.1:8900/api/v1/sql?dir=/data/tmp/data/pg_wal&start_lsn=5/BB4D55D0'
\connect db_rollback
-- pg_walex: type=truncate,xid=1243,lsn=5/BB4D9AA8,timestamp=2026-10-27 08:18:03.800537+00
BEGIN;
TRUNCATE TABLE public.tab_truncate;
COMMIT;

6.3 验证回滚的API能力

●●●SQL
[root@PGServer ~]# curl -s -H "Authorization: Bearer my-secret-token" \
  'http://127.0.0.1:8900/api/v1/rollback?dir=/data/tmp/data/pg_wal&start_lsn=5/BB4D55D0'
\connect db_rollback
-- pg_walex: type=truncate,xid=1243,lsn=5/BB4D9AA8,timestamp=2026-10-27 08:18:03.800537+00
BEGIN;
TRUNCATE TABLE public.tab_truncate;
-- pg_walex: rollback,xid=1243,lsn=5/BB4D9CF8,timestamp=2026-10-27 08:18:03.800537+00
INSERT INTO public.tab_truncate (id, name) VALUES (3, 'Charlie');
INSERT INTO public.tab_truncate (id, name) VALUES (2, 'Bob');
INSERT INTO public.tab_truncate (id, name) VALUES (1, 'Alice');
INSERT INTO public.tab_truncate (id, name) VALUES (5, 'Eve');
INSERT INTO public.tab_truncate (id, name) VALUES (4, 'Diana');
COMMIT;

总之

pg_walex让你:能读 、 能还原、 能后悔 、 能实时
让你的 DROP 不再是终点,TRUNCATE 不再靠祈祷——WAL 还在,就还有得救。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。