文章详情

短信预约信息系统项目管理师 报名、考试、查分时间动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

盘点 | 常用 PG 数据恢复方案概览【建议收藏】

2021-11-16 11:45

关注

盘点 | 常用 PG 数据恢复方案概览【建议收藏】

作者:张连壮 PostgreSQL 研发负责人

从事多年 PostgreSQL 数据库内核开发,对 Citus 有非常深入的研究。

PostgreSQL 本身不具备数据闪回和数据误删除保护功能,但在不同场景下也有对应的解决方案。本文由作者在 2021 PCC 大会的演讲主题《PostgreSQL 数据找回》整理而来,介绍了常见 数据恢复预防数据丢失的相关工具实现原理及使用示例。

在盘点数据恢复方案之前,先简单了解一下数据丢失的原因。

数据丢失的原因

数据丢失通常是由 DDL 与 DML 两种操作引起。

DDL

在 PostgreSQL 数据库中,表以文件的形式,采用 OID 命名规则存储于 PGDATA/base/DatabaseId/relfilenode 目录中。当进行 DROP TABLE 操作时,会将文件整体删除。

由于在操作系统中表文件已经不存在,所以只能采用恢复磁盘的方法进行数据恢复。但这种方式找回数据的概率非常小,尤其是云数据库,恢复磁盘数据几乎不可能。

DML

DML 包含 UPDATE、DELETE 操作。根据 MVCC 的实现,DML 操作并不是在操作系统磁盘中将数据删除,因此数据可以通过参数vacuum_defer_cleanup_age 来调整 Dead 元组在数据库中的数量,以便恢复误操作的数据。

数据恢复方案

pg_resetwal

pg_resetwal[1] 是 PostgreSQL 自带的工具(9.6 及以前版本叫 pg_resetxlog)。可清除预写式日志(WAL)并且可以重置 pg_control 文件中的一些信息。也可以修改当前事务 ID,从而使数据库可以访问到未被 Vacuum 掉的 Dead 元组。

使用示例

pg_resetwal 通过设置事务号的方式来恢复数据,因此必须提前获取待恢复数据的事务号。

1. 查看当前 lsn 位置

-- 在线查询
select pg_current_wal_lsn();

-- 离线查询
./pg_controldata -D dj | grep "checkpoint location"

通过查询来确定 lsn 的大致的位置。

2. 获取事务号

./pg_waldump -b -s 0/2003B58 -p dj
rmgr: Heap        len (rec/tot):     59/   299, tx:        595, lsn: 0/030001B8, prev 0/03000180, desc: DELETE off 5 KEYS_UPDATED , blkref #0: rel 1663/16392/16393 blk 0 FPW
rmgr: Heap        len (rec/tot):     54/    54, tx:        595, lsn: 0/030002E8, prev 0/030001B8, desc: DELETE off 6 KEYS_UPDATED , blkref #0: rel 1663/16392/16393 blk 0
rmgr: Transaction len (rec/tot):     34/    34, tx:        595, lsn: 0/03000320, prev 0/030002E8, desc: COMMIT 2019-03-26 11:00:23。410557 CST

3. 设置事务号

-- 关闭数据
./pg_resetwal -D dj -x 595
-- 启动数据库

4. 查看所需数据

select * from xx

小结

pg_dirtyread

pg_dirtyread[2] 利用 MVCC 机制读取 Dead 元组。因此可以恢复 UPDATE、DELETE、DROPCOLUMN、ROLLBACK 等 MVCC 机制操作的数据。pg_dirtyread 不存在于 contrib 目录下,因此需要单独编译。

使用示例

CREATE TABLE foo (bar bigint, baz text);
INSERT INTO foo VALUES (1, "Test"), (2, "New Test");
DELETE FROM foo WHERE bar = 1;
SELECT * FROM pg_dirtyread("foo") as t(bar bigint, baz text);
   bar │   baz
  ─────┼──────────
     1 │ Test
     2 │ New Test

小结

pg_recovery

pg_recovery[3] 与 pg_dirtyread 类似,但是使用更灵活。目前的版本中默认只返回需要找回的数据 。pg_recovery 的目标致力于数据的找回,而不仅仅是读取 Dead 元组,在后续的版本中,会增加一些辅助数据找回的调试信息,来帮助用户更快的在众多数据中找到自己需要找回的数据。pg_recovery 不存在于 contrib 目录下,因此需要单独编译。

使用示例

CREATE TABLE foo (bar bigint, baz text);
INSERT INTO foo VALUES (1, "Test"), (2, "New Test");
DELETE FROM foo WHERE bar = 1;
SELECT * FROM pg_recovery("foo") as t(bar bigint, baz text);
   bar │   baz
  ─────┼──────────
     1 │ Test

小结

pg_filedump

pg_filedump[4] 是一款命令行工具, 因此只能在服务端执行,并且不需要连接数据库。该工具可以分析出数据文件中数据的详细数据,内容格式与 pageinspect 类似。

使用示例

./pg_filedump -D int,varchar dj/base/24679/24777
 Item   1 -- Length:   30  Offset: 8160 (0x1fe0)  Flags: NORMAL
COPY: 1  a
 Item   2 -- Length:  113  Offset: 8040 (0x1f68)  Flags: NORMAL
COPY: 2  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 Item   3 -- Length:  203  Offset: 7832 (0x1e98)  Flags: NORMAL
COPY: 2  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

小结

WalMiner

WalMiner[5] 是从 PostgreSQL 的 WAL(write ahead logs)日志的解析工具,旨在挖掘 WAL 日志所有的有用信息,从而提供 PG 的数据恢复支持。目前主要有如下功能:

解析出执行的 SQL 语句的工具,并能生成对应的 UNDO SQL语句。与传统的 logical decode 插件相比,WalMiner 不要求 logical 日志级别且解析方式较为灵活。

当数据库被执行了 TRUNCATE 等不被 WAL 记录的数据清除操作或者发生磁盘页损坏时,可使用此功能从 WAL 日志中搜索数据,尽量挽回数据。

使用示例

postgres=# select record_database,record_user,op_text,op_undo from walminer_contents;
-[ RECORD 1 ]---+------------------------------------------------------------------------------------------------------
record_database | postgres
record_user     | lichuancheng
op_text         | INSERT INTO "public"。"t2"("i", "j", "k") VALUES(1, 1, "qqqqqq");
op_undo         | DELETE FROM "public"。"t2" WHERE "i"=1 AND "j"=1 AND "k"="qqqqqq" AND ctid = "(0,1)";

小结

pageinspect

pageinspect[6] 是 PostgreSQL 自带的插件,存在于源码 contrib 目录中,具备更高的稳定。

pageinspace 可以查看数据二进制的存储方式,并且可以读取 Dead 元组,因此可以用于数据找回和查看所需找回的数据是否存在。

数据结构

 struct varlena
 {
     char        vl_len_[4];     
     char        vl_dat[FLEXIBLE_ARRAY_MEMBER];  
 };

使用示例

test=# SELECT tuple_data_split("lzzhang"::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page("lzzhang", 0));
tuple_data_split                                                                                                                                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {"\x01000000","\x0561"} {"\x02000000","\xab616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161"}
{"\x02000000","\xbc020000616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161"}
(3 行记录)

小结

小贴士:保留多少 Dead 元组最合适?

因为 MVCC 机制,PG 本身自带 autovacuum,通常情况下无需手动维护 MVCC 。但autovacuum 的触发需要一定条件,数据库至少有 10% 以上的数据膨胀,严重的可能超过数据本身。

通过设置参数 vacuum_defer_cleanup_age 可保留部分 Dead 元组,减少数据膨胀对数据库产生的影响。若需要立即清理数据,可在数据存储过程调用 select * from txid_current(); 增加事务号,清空 Dead 元组。

但即使没有设置 vacuum_defer_cleanup_age ,由于 vacuum 不及时,及时操作也可以恢复出数据。

PG 数据恢复方案总结

不同方案适合的场景不同,从使用难易角度大致做了以下排名(个人建议):

  1. pg_recovery 使用简单,默认只有待找回数据;
  2. pg_dirtyread 使用简单,默认返回全部数据;
  3. WalMiner 需要对 walminer 全面掌握,并做好系统预设;
  4. pg_resetwal 需要了解的内容较多;
  5. pg_filedump 需要单独写一些脚本或工具来配合使用;
  6. pageinspect 难度极大。

若无任何准备,如何恢复数据?推荐以下方法:

  1. 及时设置 vacuum_defer_cleanup_age
  2. 安装 pg_recover 或者 pg_dirtyread
  3. 无法安装插件可以采用 pg_resetwal ,无需任何额外工具

掌握数据恢复工具使用是必不可少的,但在事故发生前采取预防数据丢失的方案更有必要。下一期我们将从 DDL 和 DML 两类操作分别介绍如何预防数据丢失的方案。

参考引用

[1]:pg_resetwal:https://www.postgresql.org/docs/10/app-pgresetwal.html
[2]:pg_dirtyread:https://github.com/df7cb/pg_dirtyread
[3]:pg_recovery:https://github.com/radondb/pg_recovery
[4]:pg_filedump:https://github.com/ChristophBerg/pg_filedump
[5]:WalMiner:https://gitee.com/movead/XLogMiner
[6]:pageinspect:https://www.postgresql.org/docs/10/pageinspect.html

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯