oceanbase任意时间点恢复时的事务一致性处理

看了很多文章介绍OB的全量、增量、日志备份,目前可以理解全量和增量备份的时候,是根据备份的时候得到的一个时间戳,到OB server的每个宏块里边,根据mvcc的原理获得一致性的备份,增量也可以这么理解。(这实际上是从TiDB的备份原理看到的,OB没有找到相应的文档)。 但是恢复到任意时间点的时候,目前只看到通过clog的的解析还原到OB server, 我的疑问从这里开始的:

  1. 每一个OB Server都有一个clog,因此加载clog是每一个ob server自己单独做的吗?

  2. 如果是单独做的,如果我指定了一个时间点,例如16:00:00,这该秒上有可能有多个分布式事务,同时这些分布式事务可能涉及到不同的ob server,因此当某一个分布式事务中的子事务在不同OB server上的提交时间不一致,例如错开了一秒(节点时间同步是不能100%一致,毫秒级差别),那么给定的这个恢复时间,有可能就会在某个observer上的子交易成功,而另外一个不会成功,从而导致整个分布式交易丢失了某些子交易。这种情况下,OB的日志恢复是否会从全局交易一致性的角度去确保这种情况下分布式交易的恢复一致性呢?

感谢

  1. 子事务的提交时间不是事务的提交时间, 事务的提交时间是所有子事务提交时间的最大值。如果事务提交成功,那么事务提交时间一定是大于等于子事务的提交时间的,恢复时间戳也就不会出现在两个事务提交点之间的情况。
    如果出现部分子事务恢复失败的情况,那说明这个事务在故障前还没有成功提交,这时候回滚所有子事务就可以了。

感谢答复,对于第二点,我理解了整体事务提交是各个子事务提交的最大值,我有两个疑问:

  1. 这个分布式事务的信息OB是一直会记录的吗?记录在哪里?跟polardb-x一样记录在某一个dn上?
  2. 假设一个分布式事务DT1在三个节点是执行:
    A节点 1s800ms
    B节点 1s950ms
    C节点 2s100ms
    在每个节点上的clog应该都是按照这个时间记录的,当然应该还有一个分布式事务的TSO记录在每一个节点的clog中(这个是我猜测,请帮我纠正),如果我指定时间点恢复是2s000ms来恢复,如果是各自节点的clog恢复,A和B应该是回滚成功的,但是C节点因为在2s100ms才commit,应该是不会加载成功的,这样就导致了DT1这个分布式事务在C节点上缺少了一个子交易。
    因为我不理解具体OB的PiTR的支持细节,所以我这么理解觉得应该有问题,希望能帮我解释一下。谢谢!

这个问题,还有人能够继续讨论一下吗?

  1. 事务提交之后会有日志记录,内存中会记录事务的提交状态,但不会持久化,可以通过日志恢复。
  2. 数据库恢复的依据是日志内容,有多少日志就恢复多少数据。而不是指定一个时间点,之后的日志都不要了,这样做当然有问题。

根据第二点,我理解为oceanbase并不真正意义上支持PiTR的功能,因为其根据时间进行假设,这本身对分布式事务在DN节点上实际执行的时间做了一致的假设,而这是不成立的。

  1. 所有数据库需要恢复到任意时间点需要做到两点:有一个全量备份(或快照),有后面的WAL日志(直到恢复时间点)。
  2. 对于ORACLE/MYSQL/DB2/PG,全量备份里所有数据不一定都是同一个快照版本,也没必要。因为有后面的WAL日志会将数据还原到一个一致性的版本。但是 OB是 LSMTree模型,数据是分层存储。OB的major freeze 恰好会生成一个全局一致性的快照版本。OB开启实时备份要求有一个完整的合并生成的全量版本加日志实时备份。这是OB的优点。
  3. 对于ORACLE/MYSQL而言,WAL日志不是实时备份。ORACLE REDO可以定期归档,MySQL的BINLOG可以滚动生成历史版本,通常在归档的那一刻进行备份。还原的时候,最坏的情形下会丢失最后一个 WAL 日志的事务对应的数据。但通常数据库都有备库,除非主备所有实例的最新的WAL日志都丢了,否则这种丢数据的概率还是很低的。对于MySQL数据库,有的开发一个 binlog agent 也可以做到从mysql实例里近实时的拉取binlog。这个可以用于数据同步,也可以算作实时热备。
    对于OB而言,WAL日志(也就是 CLOG)的备份是“近实时的”。其原理是备份agent连接到OB集群里也是作为 OB 的 WAL日志的一个副本成员(默认三副本,一个LEADER,2个FOLLOWER。备份是特殊的FOLLOWER)。它可以近实时的读取日志并备份到网络存储路径上(NAS或者OSS)。
  4. OB是分布式数据库集群,WAL日志都有三副本,但是备份的时候只需要备份其中一个副本。即使是备份一个副本,也可能存在要备份多个OBSERVER节点的WAL日志。在还原的时候,各个节点的WAL日志独立还原应用。
  5. 虽然数据库恢复的语义是还原到某个时间点,实际意思是还原到这个时间点的已提交的事务为止。对于没有提交成功的事务是不会去还原的(目前OB版本的WAL日志里应该没有未提交事务的日志,以后版本不确定)。至于分布式事务日志的还原,各个参与者的WAL日志独立应用,根据日志内容也会走到提交的最终环节。如果最终两阶段提交判断没有成功,这个就算某个参与者的WAL日志还原了(如果这个日志出现了,说明备份时分布式事务已经走到提交的后面环节),最终事务结果也不会是成功(该参与者的修改不会生效,业务是不可见)。 这种还原就是当时那个时间点分布式事务的重放。是否成功由两阶段提交协议决定。
1 个赞

感谢答复,关于1、2、3、4的答复,我没有疑问,但是第五点我有一个疑问,因为你提到了在还原的时候,会依赖分布式事务的两阶段提交机制来确保,这也是我没有理解的地方。
如果是正常的交易环节,而不是备份还原环节,我是知道会有这个处理的。假设一个分布式事务DT1分为T1和T2两个自事务,如果T1提交成功,而T2没有提交成功,此时因为2PC的机制会认为这个事务并为提交成功,这个时候在polardb-x、tdsql这些分布式数据库中会有活跃事务列表或者未完成的分布式事务记录。例如polardb-x就会存在某个节点某个表中,tdsql会存在某一个日志中,这种保留并不是长期的,而是当交易环节是会这样处理的。(我没有学习到OB是否也会有类似的分布式事务记录的地方)。
但这只是在交易环节,而不是在恢复的环节,正如你所说,每个节点都是独自还原自己的交易,假设一个分布式事务DT1有两个子事务T1和T2,而且都是提交成功的,但是T1是01秒提交(节点一上clog记录时间),T2是在02秒提交(节点2上clog记录时间),这种情况的存在是必然的,因为时间同步机制无论如何都不可能非常准确,我们能够模拟一个交易就会错开1秒,这时候给定一个恢复时间01,那么如果没有全局事务DT1记录的T1和T2,单独靠每个节点去恢复到01秒,是一定会丢失T2,除非OB持久的记录了所有的分布式事务涉及的节点,并且恢复的时候会去用这个全局分布式事务协调各个节点的恢复,否则这种情况必然会出现。
我仍然赞同你说的clog的备份是准实时的,但我们要考虑哪怕是NTP机制也会造成节点之间的时间差异,我不能确认是否每个节点的日志一定会在秒级别都拿回来,不过这个问题我不在纠结。

感谢!

OB的clog 备份会记录一个分布式事务所有参与成员的一份clog,可能涉及到多节点。
我举一个形象一点的例子。备份的时候,租户的架构是2-2-2 (租户的机器资源是集群机器资源的子集),还原的时候,租户的架构可以是单副本 1 或者单副本2,或者三副本 1-1-1 。前后两个租户的架构并无直接关联要求。
恢复(或者叫还原)的前一部分是还原一个快照(全量),后面一部分就是重做交易(REDO)。所以恢复跟交易并无本质区别。
不同的是,恢复要指定一个时间点,实际恢复的是这个时间点的被数据库承认已提交的事务。恢复出来的事务里最后一个生效时间是可能等于指定的时间点也可能小于指定的时间点(微秒级别)。以你举的 T1 T2 例子。当指定恢复时间 01 的时候,OB在恢复的时候它从clog就知道 T1是一个分布式事务的成员,并且知道还有个T2。虽然REDO 了T1的提交日志,但是在01秒那刻,没有看到 T2的 提交日志。然后日志就没了。按照2PC 机制,这个分布式事务是不成功的,所以T1的已提交大概率是不会生效的。 你可以理解为交易做到01秒时 戛然而止。

我这个说的还是有点粗,因为你说的“已提交”也粒度比较粗。 commit 下去数据库也是会分几步去做的。比如说先日志持久化,然后改变一个内部状态(这个是瞬时的,非常短,不能再拆分分析)。分布式事务 的commit也是细分2步。每个成员先持久化日志(prepare)然后发commit req给协调者,最后一步commit req 非常短,OB优化了2PC(有时候称为3PC),不用等这最后一步。你举的例子里不合理之处在于你放大了2个成员的最后一步提交时间间隔(1s很大,OB对机器时间同步误差好像是100ms以内,实际时间同步技术可以做到5ms以内)。

所以你的问题实际上是可以转变为OB分布式事务故障分析 。恢复就是REDO交易。分布式事务细节的解释可以搜索OB微信公众号里技术文章,有更详细的介绍。这里我不一定说清楚了。

感谢答复。

  1. 从你给的文章看来,每个节点的clog并没有记录一个分布式事务涉及到的所有节点的信息,而是将参与者变成一个协调者,然后通过paxos高可用保证协调者或者参与者不会宕机来做故障恢复的。而这恰恰是我在验证其他几个分布式数据库的时候所采用的方法,这导致了commit的时间在各个节点上的不一致,最终在一致性恢复的时候会丢失某个子事务。
  2. OB的两阶段提交的优化,理论上还是为了缩短各个节点上commit返回的时间,我想这也是ob在设计的时候考虑到了有可能不同节点的commit时间会不一样,这个我也模拟出来,在非常大量的数据量的时候,极易出现从毫秒级到秒级的累积差异,导致各个节点的commit会差一秒。
  3. 至于时间处理能够达到5ms这种程度,我也想请教一下当前除了google采用原子钟+GPS号称能做到7ms差异的情况下,什么样的时间同步机制能够做到5ms?OB实际上的时间差异还是依赖类似NTP或者Chrony吗?如果还是这种,那么时间差异是不能确保的。
    4.如果你假设我的情况存在(当前OB用了很多方式去规避这种方式),在你描述中说到的“按照2PC 机制,这个分布式事务是不成功的,所以T1的已提交大概率是不会生效的”,这里的机制意味着当前的分布式交易会按照2PC提交机制,也就是那时候会有一个参与者被当成协调者,而且这些交易数据会100%按照交易的流程执行吗?这也是我困惑的地方,分布式事务apply日志的时候,是否一定是按照交易的机制来做,因为每个节点是自己在apply clog,除非是集中apply clog。

感谢!

继续阅读了一些文档,发现你说的一些点是错误的:

  1. clog的apply并不是observer各自apply各自的,因为在备份的时候所有的observer的clog是经过合并处理的,也就是按照事务经过整理的,从我的实验来看也是这样,observer上的clog与归档出来的clog完全不一样。
  2. 在恢复的时候,我原来一直根据你的思路在思考,认为每个observer的clog是自己在apply,所以我一直困惑对于一个分布式事务是如何去还原的,但是经过阅读文档发现恢复的时候,并不是这样的,而是agentserver会把clog下载下来,然后合并,在写入,这就类似在交易的时候从一个client端发起一样了。

如果我的理解成立,那么ob的恢复实际上跟传统数据库的恢复不同,对于一个庞大的ob,如果真的要这样恢复,我觉得其效率是很有限制的。

同时,我还有如下几个问题请帮助释疑:

  1. OB对于整集群的恢复,不支持异机恢复,我猜测其根本原因是因为sstable中的分片信息不能修改的问题,tidb有rewrite的功能,实际上ob按照租户恢复,也是可以恢复到异机的,所以整体集群恢复与单租户恢复实际上方法是不一样的,我可以理解为ob的整体集群恢复是直接将文件拷贝回去吗?如果不是,为什么整集群恢复不能支持异机恢复?
  2. 在OB企业版本3.2.3这里,整集群恢复的优先级是不是优先clog,如果没有clog,才是全量+增量这种方式?这个跟传统数据库备份恢复又有很大不同,是不是因为全量+增量的合并过程远远慢于全量+clog的加载过程?

以上希望得到大师的答复。

1 个赞
  1. 我可能没有理解你说的这个 Case 。我建议你单独发你的测试Case重现步骤,这样方便大家看懂 理解参与讨论以及OB研发解答。
  2. OB的实现是能容忍节点之间时间有一定误差,2.x的时候要求还比较苛刻,要求 100ms 以内,现在4.0发版说可以支持2s,说明OB在这块技术实现又做了优化。这个原理和实现方法,无论是老版本还是新版本我也解释不清楚。相信后面 OB 会针对4.0的创新技术有专门的分享,建议你准备相关问题到时候跟讲师直接交流。
  3. 时间同步做到5ms 以内这是 NTP 技术,跟OB 没有关系。我说能做到5ms 是我实际的运维经验看到的。NTP的原理可以网上搜索一下。 OB的全局一致性版本把对时间同步的依赖降低了,对时间同步的要求依然还在。后面建议参照第 2 点。
  4. 关于分布式事务的恢复,我前面的答复都是从原理上推测。我不是数据库研发,所以对工程实现方面没有经验。我估计你是研发,你的问题也建议在后面OB公开的交流中去咨询讲师。
    从原理上我认为,分布式事务恢复的时候,也是多个参与者的事务都要REDO。注意这里说的是多个参与者,不是多个节点(如果我前面说法误导了,那我纠正一下)。从原理上分析时,并不关注这多个参与者是否在一个节点还是多个节点。所以我的推断是不关心是集中式apply 还是多线程并行apply。 OB的备份恢复在实现上会有个从无到有,从有到优化的过程。为了追求恢复的性能,后期应该会有并行 apply 技术。至于是单节点内并行还是多个节点上并行,只是实现方面的考虑。 针对实现原理的推测也可能不准。

补充一些建议:
你的问题建议拆分为几个独立的问题,保持每个问题的单纯性,在细节上可以详细一点,这样也许OB专家会给出更准确的解答。

    1. 分布式事务原理
    1. 全局时钟原理
    1. OB备份恢复原理

恩。
我是运维,分析问题主要是原理上推测。前面的分析和文章都是基于对OB1.X/2.X版本的理解做出的。由于不是研发,对于工程实现的理解可能会存在不对。如果发现不对,以文档和OB专家的解释为主。

  1. 在apply clog时,不关注节点,只关注clog的内容。备份确实是把多个 observer的clog 合并存放了,跟原始的clog 不完全一样(推测是在顺序上)是可以理解的。具体如何实现应该是在遵守ACID基础上让apply的效率更高(目标是并行apply,挑战是事务的一致性。分布式理论上的一致性概念很多,恢复能做到哪个层次,看实现能力。不展开这个)。
  2. 恢复的时候就是 redo 事务。遇到分布式事务,是多个参与者都在redo。如果我前面的解释或文章误导了你以为多个节点在redo,那这里我纠正一下。

新增的几个问题:

  1. OB集群的恢复不支持异机恢复,这个我不太理解。我没找到这个说法。因为OB集群时多租户,对集群的备份恢复会分拆为对多个租户的备份恢复。这里有个特殊的租户就是内部租户的备份与恢复。 我初步认为这个是没有必要的。业务使用的是租户,一个租户不管是在当前集群恢复出来还是在其他集群恢复出来,只要业务能访问使用即可。sys租户是否要备份我不确认,如果要做估计会有面临先有鸡还是先有蛋这种问题。其实OCP元数据记录了OB集群的一些元数据信息,从OCP 里“恢复”一个集群可能更方便。这个也不展开了。
    OB的备份和恢复时解耦的,不要求是同集群,也不要求节点数一致或者资源一致。恢复就是重做交易,完整的说法是在某个快照基础上重做后面的交易。当然OB的快照备份(全量备份)也不是简单的拷贝文件(如果你单独去看看OB数据文件的介绍就不会这么认为。OB数据文件就一个大文件 :slight_smile: )。
  2. OB的备份恢复大致思路跟传统数据库是一样的,要全量加增量。理论上如果你有集群诞生到现在的所有 增量(clog),你可以没有全量也能恢复。这是理论,实现上 OCP备份链好像要求一定要做个全量合并,所有没有全量就不能恢复。 这个要求对运维不过分,因为默认每天就有一个全量合并。

再补充一些建议:

  1. 建议先从正向逻辑去理解 OB全局的架构原理。 即看OB 文档分享说的,先看这个逻辑是否合理闭环畅通。然后再根据经验从细节处提一些问题。
  2. 撇开从代码上研究备份与恢复原理,可以构造一些试验去研究。从简单到复杂。最复杂最全面的Case就是备份一个 2-2-2架构的租户数据恢复到另外一个 2-2-2的租户里。原租户分区打散,构造分布式事务。观察clog以及 OB事件表和备份恢复相关视图。

感谢答复,从目前我理解到的知识,我基本上明白了一些原理,我还在构建测试用例,不过从本质上说OB的恢复与其他基于mysql和pg的恢复是不一样的,我之前也在其他场合咨询过为什么不采用rocksdb的另外一种纯粹的物理备份方式,没有非常明确的答复。
这些都跟设计者有关,我觉得恢复性能如何,包括备份、恢复的方便性如何,等待市场的检验,从我目前得到的信息看,分布式数据库的备份与恢复面临的挑战非常大,虽然有些厂商号称支持,也认证,但是我相信只是单纯的商务行为,从技术角度,还有很多问题需要探讨并解决。
感谢你的答复,这个帖子就到这里吧。
谢谢!

1 个赞