关于数据库:盘点-常用-PG-数据恢复方案概览建议收藏

53次阅读

共计 6722 个字符,预计需要花费 17 分钟才能阅读完成。

作者:张连壮 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_resetwal 复原数据操作及时,数据相对可复原。
  • 在 SERVER 端操作所需权限较高,云数据库可能无奈应用。
  • 若 DDL 数据无奈找回,尽管元信息曾经复原,但数据曾经不在磁盘上。ERROR: could not open file "base/16392/16396" 表明文件或目录曾经不存在了。
  • 启动数据库后,不能够进行任何影响事务号的操作。否则晋升事务号将导致数据再次不可见。
  • 通过 pg_resetwal 复原数据前,需将数据 PGDATA 目录进行全量备份,只复原所需数据
  • pg_resetwal 操作难度大,须要把握的 PG 常识较多。

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_dirtyread 应用十分不便,仅须要装置一个插件便能够找回数据。
  • pg_dirtyread 会返回全副数据,蕴含未被删除的数据。例如示例中 bar=2 的数据。
  • 基于 MVCC 机制的操作只能实现 DML 的数据找回。

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_recovery 的指标是用于数据找回,因而应用起来更不便。在将来的版本中,也会退出更多辅助数据找回的性能。
  • pg_recovery(recoveryrow => false) 能够读取出全副数据。
  • pg_recovery 只能找回 DML 的数据。

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

小结

  • pg_filedump 能够间接读取文件,无需连贯数据库,实用于重大劫难的状况。然而须要晓得具体的文件地位,适用性不强。
  • pg_filedump 可间接通过 SQL 将数据一键找回,须要编译找回数据办法。
  • pg_filedump 无奈找回自定义数据类型的数据。
  • pg_filedump 因为只能在服务端执行,不适用于用于云数据库的数据找回。

WalMiner

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

  • 从 WAL 日志中解析出 SQL,包含 DML 和大量 DDL

解析出执行的 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)';

小结

  • WalMiner 通过 WAL 日志进行找回,只有日志保留量足够,便能够找回数据。
  • WalMiner 能够通过与存储过程的联合,来实现一键数据找回的性能。

pageinspect

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

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

数据结构

 struct varlena
 {char        vl_len_[4];     /* Do not touch this field directly! */
     char        vl_dat[FLEXIBLE_ARRAY_MEMBER];  /* Data content is here */
 };

应用示例

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 行记录)

小结

  • pageinspacet 通常用于底层数据存储的剖析,极难复原数据,简单的自定义数据类型,复原更加艰难。尽管能够找回数据,但 不举荐
  • 数据不直观,例如 {"\\x01000000","\\x0561"}
  • 数据的先后顺序,须要参考 pg_attribute 来获知返回的数据对应的列。
  • 须要对 PG 源码深度把握,同一数据类型不同长度数据格式不同。例如"\\x0561","\\xab6161","\\xbc020000616161”,61 代表字母 a

小贴士:保留多少 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/do…
[2]:pg_dirtyread:https://github.com/df7cb/pg_d…
[3]:pg_recovery:https://github.com/radondb/pg…
[4]:pg_filedump:https://github.com/ChristophB…
[5]:WalMiner:https://gitee.com/movead/XLog…
[6]:pageinspect:https://www.postgresql.org/do…

正文完
 0