作者:攒叶 夏花
引言
闪回技术,顾名思义,是指数据库系统提供的一种能力,允许用户查看和恢复到过去某个时间点的状态,或者回滚特定操作,而无需依赖传统的备份与恢复机制。这一功能极大地增强了数据库的灵活性和可靠性,为数据库管理员和开发人员提供了一种快速响应错误、审计数据变更以及进行问题诊断的有效手段。
闪回典型场景
目前闪回查询的典型应用场景如下:
- 误操作修复:快速恢复因误删除或误更新导致的数据丢失。
- 数据恢复演练:在不影响生产环境的情况下,进行数据恢复的测试和验证。
- 问题诊断:通过回溯历史数据状态,帮助快速定位并解决数据库性能问题或异常。
- 合规审计:提供数据变更的历史记录,支持审计和法务调查需求。
闪回技术方案
作为一种数据库企业级能力,闪回查询目前在业界内有如下方案:
数据库日志逆向重做
产生与历史数据变化相反的操作执行集合,重放到原库或某备份库上。典型的案例如 MySQL。MySQL 通过 BINLOG 日志以及相关的三方工具(如 mysqlbinlog_flashback, binlog2sql 等),可以将数据库闪回到过往的某个时间点。 这种方案存在一定的限制,比如通常需要要求 BINLOG 的格式为 FULL,在使用上也缺乏灵活性,另外在性能和执行效率上也并不高效。
System-Versioned Tables
典型的数据库如 Mariadb。System-Versioned Tables 是一种特殊的表,核心思想是将记录的当前版本和历史版本都存放在表上。为了区分出所有的版本,表上还会被默认加上一些列来表达版本信息,如行记录的产生时间,或者行记录产生的事务 ID 号等。 该方案提供了良好的灵活性,用户可以使用 SQL 这样的方式来读取特定的历史版本数据,或者通过 SQL 直接进行数据的闪回。同时,该方案允许以表粒度的方式来控制是否需要保留历史版本数据。 然而,该方案存在的两个缺陷,导致其并没有被广泛使用:
- 数据库并不会负责对版本进行清理,用户需要显式清理历史版本
- 历史版本均保存在用户表上,查询时会扫描到许多不相关的历史版本记录,对在线业务查询会带来不容忽视的影响
Undo 方案
典型的数据库如 Oracle。该方案与 System-Versioned Tables 一样,同样支持通过 SQL 查询来操作和访问历史版本数据。 但相比于 System-Versioned Tables 方案,此方案的显著特点在于历史版本的物理隔离——历史版本由专有区域 Undo 维护,而当前活跃数据继续驻留在用户的在线表空间。 这种分离策略优化了资源利用,确保了主数据区的性能并减轻了由历史数据累积可能导致的负荷。历史数据的高效组织和自动生命周期管理进一步减轻了维护压力,使得用户不必手动介入数据的清理和空间回收过程。
PolarDB-X 多级闪回方案
通过上述分析,用户实际上在做一个困难的选择。那么有没有一个方案可以兼顾空间、性能和使用成本,并且还不需要业务做的改造?我们认为答案就在 PolarDB-X 的多级闪回方案。
PolarDB-X 存储引擎核心技术 Lizard 多级闪回
如上述架构图所示,依托于 PolarDB-X Lizard 事务引擎的能力,用户的数据版本按照层次被存放在多个区域。其中核心区域:一级闪回以及二级闪回区域,支撑了用户对于闪回查询的多维诉求。以下将分别讨论一级闪回以及二级闪回的设计。
一级闪回
一级闪回方案
过往 MySQL InnoDB 存储引擎 Undo 管理是面向在线活跃视图,并且基于 Read View 的设计无法很好地表达事务的版本信息,因此在设计上不支持闪回能力。PolarDB-X 存储引擎基于 Lizard 事务系统,通过三个组件支撑了一级闪回能力。
- Lizard Transaction Slot
查询可见性取决于数据库视图以及对应记录的真实版本信息。产生该记录的事务,其版本信息由 PolarDB-X Lizard 事务引擎的 LTS 组件所维护。
2. Lizard Snapshot Manager
PolarDB-X Lizard 事务引擎用逻辑时间系统提交号 SCN 来表达本地事务提交顺序,用全局逻辑时间 GCN 来表达分布式事务的全局提交顺序。为了满足用户侧对物理时间的强诉求,PolarDB-X Lizard 事务引擎提供内部表以及打点机制来维护逻辑时间与物理时间的对应关系。
3. Lizard Space Manager
PolarDB-X Lizard 事务引擎接管了历史版本数据在 Undo 区域的流转,历史版本数据清理不再只取决于当前可见性,而会更多考虑未来可见性。未来可见性可以由两个维度来衡量:
- 时间维度
确保历史版本在某段时间范围内仍然可见,被 innodb_undo_retetion 全局参数决定
- 空间维度
空间有盈余的情况下,尽可能保留更多的历史版本数据, 被 innodb_undo_space_reserved_size 全局参数决定
一级闪回接口
通过对全局参数的设置,来开启一级闪回能力
SET GLOBAL innodb_undo_retention = 1800;
通过灵活的 SQL 来访问一级闪回区域
SELECT * FROM t AS OF TIMESTAMP $timestamp SELECT * FROM t AS OF SCN $scn SELECT * FROM t AS OF GCN $gcn
其中上述 AS OF 子句作用于表 t,并支持标准的 SQL 语法,如后续可以接入任意的 WHERE 子句等等。
一级闪回讨论
一级闪回区域维护了一段时间(如 1800s )内的所有历史版本,该区域的特点如下:
1) 一级闪回区域内的数据被组织成版本链,通过链式回溯,调用者可以查询任意想要的版本信息
2) 一级闪回区域占据了在线的存储空间,并使用了索引节点,因此历史版本查找非常高效且直接
3) 一级闪回区域面向实例级别,数据库所有的修改版本均被保留 一级闪回区域具有与普通查询几乎相当的查询效率,并且保留了整库的历史版本信息。
然而,一级闪回区域作为一个实例级别的能力:
1)侵占了用户的在线存储空间
2)保留了部分的索引节点,对在线普通查询可能存在一定的影响
3)不具备细粒度的表级闪回管理能力。 因此其保留时间通常不宜设置过长。目前一级闪回查询,在 PolarDB-X 分布式数据库中,被广泛用于短时间内的一致性闪回查询。
二级闪回
二级闪回方案
独立区域
二级闪回区域是 PolarDB-X 在一级闪回区域之外重新设计的一片区域。当用户创建了 Flashback Area 表后,其历史版本如果超过一级闪回的保留周期,则会被挪移到二级闪回区域。二级闪回区域的历史版本会脱离掉一级区域的管理,并由独立的空间回收系统来维护。由于二级闪回区域与一级闪回区域在物理上进行了隔离,因此二级闪回存储区域未尝不可存储在廉价的存储设备上,如阿里云的 OSS 服务上。
空间管理
二级闪回区域同样采用高效的空间自管理模式,用户只需要设置好保留的时长,历史版本则会被妥善地维护。由于二级闪回区域只保留了特定表的历史版本数据,所以其数据空间的使用量会大幅度得到降低。这意味着二级闪回区域的历史版本数据能够被保留足够长的时间,比如 7 天。
表级管理
引入新类型的表:Flashback Area Table。Flashback Area Table 具备以下特点:
1)依托于 Lizard 事务引擎提供的灵活的控制能力,用户可以自主选择将某些表设置为 Flashback Area Table
2)Flashback Area 作为表的属性,其生命周期会被妥善地维护,如会被同步到备库并产生合理的效果
3)Flashback Area Table 的历史版本会被腾挪到二级闪回区域
4)Flashback Area Table 的大量索引节点会随着对应历史版本进入二级闪回区域而被清除,有效地降低了开启闪回查询后对在线常规业务的影响
二级闪回接口
用户可以通过下面的方式指定创建支持 Flashback Area 能力的用户表:
mysql> SET OPT_FLASHBACK_AREA = 1; mysql> CREATE TABLE t (id INT PRIMARY KEY, sec INT, KEY(sec)); # 通过 INFORMATION_SCHEMA.INNODB_TABLE_STATUS 观察表属性 # flashback_area 来确定是否已经正确开启该能力 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLE_STATUS; +----------------+------------------+------------------------+ | SCHEMA_NAME | TABLE_NAME | options | +----------------+------------------+------------------------+ | test | t1 | ...flashback_area=1... | +----------------+------------------+------------------------+
当需要进行二级闪回查询时,用户可以采用如下方式:
mysql> SET query_via_flashback_area = 1; mysql> SELECT * FROM t1 AS OF TIMESTAMP $snapshot_gcn; +----+----+ | id | c1 | +----+----+ | 1 | 10 | +----+----+
二级闪回区域的历史版本保留周期脱离了 innodb_undo_retention 的设置, 而使用了 innodb_txn_retention 进行设置:
mysql> SET GLOBAL innodb_txn_retention = 604800;
二级闪回讨论
二级闪回克服了一级闪回上遇到的典型问题,具有以下优势: 1)面向表对象级别的管理,用户可以灵活选择 2)大幅度降低了在线表的索引节点 3)独立于一级闪回区域,历史数据可以存留足够长的时间以应对闪回查询需求
多级闪回架构优势
PolarDB-X Lizard 事务引擎通过引入分层数据版本存储结构,实现了对历史数据的高效管理与优化闪回查询能力。该结构分为三个层次:当前数据区域、一级闪回区域和二级闪回区域,这三者共同构成了数据库的多维时间维护系统。
- 当前数据区域
PolarDB-X Lizard 事务引擎优化了对最新数据版本的事务状态信息访问,确保常规查询与更新操作的高效率,该区域是整个数据存储结构中的访问热点。
- 一级闪回区域
提供了一个时间窗口内历史版本的临时存储,支持短期内的数据回溯查询。其设计使得 PolarDB-X 可以支持分布式一致性闪回读取,强化了数据库在处理并发操作时的数据完整性和一致性。
- 二级闪回区域
二级闪回区域针对更长时间跨度的历史数据版本进行存储,减轻了长期历史数据对主存储区域的压力,有效降低了在线热数据区的维护成本,其设计可允许将旧数据迁移到成本更低的存储介质上。这不仅节约了存储成本,还为闪回操作提供了灵活且高效的支撑。 用户可以通过标准SQL语句轻松地执行回档查询,无需关心数据实际存放的具体位置。另一方面该区域支持以表为单位进行历史数据的维护,提供了更灵活、更普适的使用手段。
PolarDB-X 的这一分层历史数据存储架构是实现高效闪回查询的核心,这种创新允许数据库维护长期的历史版本,同时确保查询性能和数据可用性不受影响。这为用户提供了十分便捷的数据时光旅行能力,让数据恢复和变更追溯变得更为简单和可靠。
闪回方案对比
以下将从空间成本、性能成本、使用成本三个维度上对比目前主流的闪回方案。
空间成本
在现代数据库系统中,存储成本的分层策略普遍基于存储介质的性能指标、服务质量保证(SLA)、及其经济效益。 根据业务形态,可以划分为两类型存储服务:
业务类型 | 存储形态 | 概述 | 成本 |
业务在线储存空间 | 本地 SSD 或等同云盘 | 用于在线业务 | 每 GB 每月 0.8~1.6 |
业务离线归档空间 | OSS 存储服务等 | 用于归档或备份业务 | 每 GB 每月 0.1~0.2 |
数据库日志逆向重做
基于数据库日志的闪回方案在存储成本控制方面显示出天然的优势。此类方案中的日志文件通常保存在成本更低的存储介质上,如阿里云 OSS 或 Amazon S3。 这类存储介质的价格大幅低于在线高性能存储空间,并且适用于长期数据保留。 廉价的存储解决方案使得保留更长时间的历史数据成为可能,如 PolarDB-X 通常将 BINLOG 文件保留达 7 天。
System-Versioned Tables
在 System-Versioned Tables 方案中,历史版本数据的存放位于用户的在线表空间,直接占用了宝贵的高性能在线存储资源。
Undo 方案
尽管 Undo 方案通过分离历史数据和在线表空间以提升管理的灵活性,但它依然占用了高性能在线存储。这一设计随着历史数据的增长将推高存储成本,影响整体的成本支出。 实际测试表明,极端场景如 Sysbench Write Only 场景,Undo 空间的快速增长(每小时约 90 GB)必然导致显著的存储成本上升。 鉴于此,实践中通常会限制历史版本数据的保留时间,以防止存储成本失控。例如,PolarDB-X 推荐的历史版本数据保留时间为 1800 秒。
PolarDB-X 多级闪回
支持多维度、多梯度的存储成本设计,目前支持与普通的 Undo 区域进行物理隔离,未来可支持存储形态隔离。
性能成本
闪回查询对于在线业务查询的影响是不容忽视的。
数据库日志逆向重做
基于数据库日志的闪回方案,对在线表空间 0 侵入,因此对于在线业务不会带来任何额外的影响。
System-Versioned Tables
System-Versioned Tables 将所有的历史版本都存放在用户的在线表空间上,这些历史记录对于大部分的在线业务查询都是不可见且无意义的,但其查询开销并不会因此而节省。因此 System-Versioned Tables 的查询性能会随着时间增长而逐渐下降。
Undo 方案
Undo 方案虽然将历史版本和在线表空间进行了分离,大幅度降低了对在线业务的冲击,但在我们的测试中发现,某些极端场景下仍然会对在线业务的性能造成冲击。
PolarDB-X 多级闪回
对在线表侵入程度降到最低,实验测试结果显示在极端压测场景下并不会对在线业务产生影响。
使用成本
在使用成本上我们认为可以从三个维度上进行对比:访问接口,空间回收,表级管理。
数据库日志逆向重做
1)访问接口 基于数据库日志的闪回方案在性能成本和空间成本上有压倒性的优势,但是由于其糟糕的使用方式、以及种种的限制条件,导致其几乎是不可用的。典型的案例是,当需要将某张表的回档时,通常需要下载数据库日志,并利用三方工具将日志进行逆向解析,随后将逆向 DML 过滤并在原库上进行重放。整个操作期间无法回滚无法停止,并且回档效率非常低效。
2)空间回收 其次其空间回收需要依赖于的管控平台任务流,并不受到数据库本身控制。
3)表级管理 对表级管理只有有限支持: 支持表粒度级别的闪回,但由于日志组织通常并非按照表对象进行组织,因此在对表对象进行闪回时效率较低。 不支持表粒度级别的日志归档。
System-Versioned Tables
1)访问接口
支持灵活的 SQL 语句进行版本回溯以及数据回档,同时支持事务性操作,操作安全可靠。在易用性、以及使用成本表现出非常强的优势。
2)空间回收
需要用户进行显式的历史版本的维护和管理,有较高的维护成本。
3)表级管理
支持表粒度的历史版本保留。
Undo 方案
1)访问接口
支持灵活的 SQL 生态,以及支持事务性操作。
2)空间回收
支持空间自动回收机制。
3)表级管理
该功能面向实例级别,不支持表粒度的历史版本管理。
PolarDB-X 多级闪回
1)访问接口
同样支持灵活的 SQL 生态,以及支持事务性操作。在数据库侧原地访问,数据库屏蔽多级闪回区域的细节,不需要跨多平台。
2)空间回收
多个层次均支持空间自动回收机制。
3)表级管理
支持表粒度的历史版本管理,并且支持保留超长的历史版本数据。 下表则显示了目前主流的闪回方案对比:
Flashback 方案 | 空间成本 | 易用性 | 表级粒度 | 业务表侵入 | 灵活性 | 保留时长 | 空间自管理 | 回溯耗时 |
基于数据库日志 | 低 | 低 | 有限支持 | 无 | 无灵活性 | 高 | 无 | 漫长 |
System-Versioned Tables | 高 | 高 | 支持 | 高 | 支持 SQL | 低 | 无 | 快 |
Undo | 高 | 高 | 不支持 | 高 | 支持 SQL | 中 | 有 | 快 |
PolarDB-X 多级闪回 | 中 | 高 | 支持 | 低 | 支持 SQL | 高 | 有 | 快 |