建议收藏,数据库为什么会丢失数据?(下)

上篇详细介绍了问题类型,下篇将重点分享一些有价值的预防措施。针对PostgreSQL,整理了一下现有的预防措施。

备份大法

最先想到的就是备份大法,不管是pg_dump等逻辑备份,还是cp、pg_basebackup等物理备份,还是存储级别的快照备份,都可以实现目的。然后结合归档WAL日志,实现PITR,不过需要确保有误操作前的全量备份和所有WAL归档。因此RTO和RPO的选择也同样至关重要。

建议收藏,数据库为什么会丢失数据?(下)

Standby数据库

这个也是能想到的另一种方法,当主库服务器异常时,备库可以快速提升为主并提供服务,同时备库的存在,也提供了数据库的另一个副本,主库数据丢失后,备库还有一份数据。另外,还有强大的"延时备库",recovery_min_apply_delay,设置备库延迟重做WAL的时间,而备库依然及时接收主库发送的WAL日志流,只是不是一接收到WAL后就立即应用,而是等待此参数设置的值再应用。注意若synchronous_commit=remote_apply,主库每插入一条语句都需要延迟recovery_min_apply_delay该参数这么久才能继续写。比如recovery_min_apply_delay = 24h,主库上不小心删了一张表,那么你还有24小时的时候在备库上进行挽救操作。

建议收藏,数据库为什么会丢失数据?(下)

控制vacuum

我们知道在PostgreSQL的MVCC实现方式中,死元组并不会立即删除,而是由后台vacuum进程去定期清理那些"不可见"的死元组。所以还有一种操作是,把autovacuum设为off,关闭后台自动清理进程,由自己手动去执行vacuum的动作,这样那些未执行过vacuum的表里的死元组就会一直保留,然后通过pg_resetwal"篡改"数据库的事务号,达到数据可见的目的。注意关闭autovacuum会导致表膨胀,除非你知道自己在干什么,否则不要关闭autovacuum,对更新频繁的数据库或表更要慎重使用这一技巧。并且这种方式不适用于drop table,vacuum full和truncate等DDL,会提示/base/xxx not exists,因为原来的数据文件已经被删了。


另外一个可以控制vacuum的参数较vacuum_defer_cleanup_age,延迟多少个事务进行清理,比如设置为100,也不会立马删除,留下抢救的时机。

建议收藏,数据库为什么会丢失数据?(下)

回收站

pgtrashcan垃圾回收工具,就像windows中的回收站,删除了文件后,是放在回收站的,可以选择还原,找回相关文件。同样,当我们删除PostgreSQL表后,表并不会立即物理删除,而是先保存到回收站中,在需要时可以恢复表。当DROP TABLE命令执行后,表会被移到一个名为"Trash"的schema下,如果想永久删除此表,可以删除"Trash"模式下的这张表或者删除整个"Trash" 模式,这个pgtrashcan仅对表有效,其它数据库对像被删除后不会转移到"Trash"模式。

反向生成undo

PostgreSQL因为没有undo的原因,但是由于有WAL的存在,WAL日志里面记录了对数据文件的修改,所以这里就要使用到另一个工具walminer了,首先向作者致敬,真是一个十分给力的工具。

这个是一个类似MySQL中的binlog2sql的日志解析工具,通过walminer,可以逆向解析出undo sql,如下,比如误删一条数据,那么拿出相应的undo sql重新insert一下即可。这里引用一下作者的原图:

ØDELETE语句解析原理

建议收藏,数据库为什么会丢失数据?(下)

ØINSERT语句解析原理

建议收藏,数据库为什么会丢失数据?(下)

篡改事务状态

从PostgreSQL多版本实现的原理上,通过篡改事务状态找回数据也是有可能的。因为PostgreSQL的多版本原理是旧数据并不删除:

1)对于删除数据的操作,只是把行上的xmax改成当前的事务id

2)对于更新操作,只是把原先行上xmax改成当前的事务id,并插入一个新行,而新行上的xmin置为当前的事务id

事务的状态是记录在commit log中的,如果事务提交,只是把commit log中相应的事务状态改成"已提交状态(TRANSACTION_STATUS_COMMITTED )",如果事务回滚,则把commit log中的事务状态改成"事务回滚(TRANSACTION_STATUS_ABORTED )"

所以从理论上说,只要把在commit log中刚提交事务状态从"TRANSACTION_STATUS_COMMITTED"改成"TRANSACTION_STATUS_ABORTED",原先的事务就会做废,就能回到事务之前的状态。

但同时tuple上面还由于有infomask标志位的存在,加速获取事务状态。在PostgreSQL中提供了TransactionIdIsInProgress、TransactionIdDidCommit和TransactionIdDidAbort用于获取事务的状态,这些函数被设计为尽可能减少对CLOG的频繁访问(假如把freeze相关参数设置为20亿的话,那么clog最多可能达到500多MB,每一个事务占2bit)。尽管如此,如果在检查每条元组时都执行这些函数,也可能会成为瓶颈。

建议收藏,数据库为什么会丢失数据?(下)

在读取或写入元组时,PostgreSQL会择机将提示为设置到t_infomask中,比如上面的例子,PostgreSQL检查了元组的t_xmin对应事务的状态,结果为commited,那么就会在元组的t_infomask中置位一个HEAP_XMIN_COMMITTED,表示这条元组已经提交了,如果设置了标志位,那么就不再需要去调用TransactionIdDidCommit和TransactionIdDidAbort去获取事务的状态,可以高效地检查每个元组xmin和xmax对应的事务状态。

所以要想恢复数据,还需要把相应表文件中各行上的t_infomask状态中的hint标志位给清除掉之后,数据才能恢复回来。为此,唐成老师专门写了一个工具,pg_fix,https://github.com/osdba/pg_fix,直接修改表中数据和commit log中事务的状态,注意生产上慎用。

闪回

Oracle支持强大的闪回,闪回特性使用场景:

1)flashback database:数据库闪回;多用于数据库恢复,数据库、用户、表空间误删。

2)flashback table:表闪回;用于数据表恢复;数据表误删。

3)flashback query:闪回查询;应用于修复误操作数据。

文章部分素材源自:PostgreSQL学徒

展开阅读全文

页面更新:2024-05-24

标签:数据库   目的   数据   预防措施   回收站   语句   备份   原理   标志   状态   事务   操作   建议   文件   收藏

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top