一旦发生数据丢失、数据损坏,造成的影响就会非常大,这就要求业务系统有一个完善的机制以应对这些场景带来的灾难(服务器宕机、数据库崩溃或损坏、硬件故障等),比如之前的案例,2018年,腾讯云硬盘由于磁盘静默错误,导致创业公司线上生产数据完全丢失。为此,常见的应对方式有备份、冗余、灾备、快照、高可用等等。对于数据库来说,还有闪回等方式。
服务器硬件简单来说就是CPU + 内存 + 磁盘(磁盘控制器也是一个重要的组成),对于一般的服务器优先级来说,主要都是受限于CPU,主要因为:
从PostgreSQL多版本实现的原理上,通过篡改事务状态找回数据也是有可能的。因为PostgreSQL的多版本原理是旧数据并不删除:1)对于删除数据的操作,只是把行上的xmax改成当前的事务id2)对于更新操作,只是把原先行上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中使用了相关标志位,如下:#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */在读取或写入元组时,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中的一系列闪回方法:PgSQL 应用案例 PostgreSQL flashback(闪回) 功能实现与介绍
可以看到,数据库为什么会丢失数据有诸多原因,包括人为的、硬件故障还有本身数据库的复杂实现,这还不算上分布式数据库要实现的那一套CAP、BASE理论,所以对于PostgreSQL来说,备份一定是重中之重,也是最简单粗暴有效的方式。若备份因为种种原因失效了,那么还有各种各样的强大工具供我们使用,如walminer、pg_fix、回收站等等。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!