跳转到主要内容
Chinese, Simplified

使用微服务,架构师希望拆除单片数据库并复制数据,而不是共享数据。然后,需要对修改完成的地方(如CQRS中的C)进行审计。为了恢复,Oracle数据库已经这样做了,在修改数据块之前构建重做记录,但这是一个物理变化矢量。我们需要一些有更多可能性的逻辑来过滤和转换。有多种可能的方法。但不幸的是,自从Oracle收购了Golden GAte并将其单独出售后,数据库中构建的那些就慢慢被删除了。

  • 流在12c中被弃用
  • 在12c中不赞成高级复制
  • 更改数据捕获在12c中是不赞成的
  • LogMiner连续矿在12c就被废弃了

deprecated变成了desupport,甚至在以后的版本中被移除,比如19c的Continuous Mine——12cR2的最终路径集:

ORA-44609: CONTINOUS_MINE is desupported for use with DBMS_LOGMNR.START_LOGMNR

 

文档表示,替代产品是“Golden Gate”,但那是另一种需要购买的产品,功能强大但价格昂贵(而且没有标准版)。

Debezium dbz - 137

Debezium是一个用于更改数据捕获的开源分布式平台,它正在开发一个Oracle数据库连接器。许多想法在https://issues.jboss.org/browse/DBZ-137中被提及,在这篇文章中我给出了我的想法。

甲骨文xstream

完美的解决方案,因为它对源代码的开销最小,而且非常高效。但是它需要获得Golden Gate许可,因此可能不是开源产品的最佳解决方案。

甲骨文LogMiner

LogMiner包含在所有版本中,读取重做流(归档和在线重做日志)并提取所有信息。在启用补充日志记录时,我们有足够的信息来构建逻辑更改信息。许多解决方案已经基于此。但我认为它有两个问题。

LogMiner限制:

基本上,LogMiner不是用于复制的。这个想法更多的是提供一个故障排除工具来理解数据上发生了什么:什么导致了太多的重做?谁删除了一些数据?哪些会话锁定了行?有一些限制,比如不支持的数据类型。它的设计不是为了提高效率。但也有可能在另一个系统上进行开采。但是,我认为这些限制对于简单数据库上的开放源码解决方案来说是可以接受的,因为它的更改率很低。

LogMiner的未来:

更让人好奇的是,Oracle是如何去掉那些可能会替代Golden Gate的特性的。在19世纪,持续的 CONTINUOUS_MINE 被移除。这意味着我们需要不断地打开和读取整个重做日志。当甲骨文在未来的版本中看到一个与Golden Gate竞争的健壮的开源产品时,我们知道甲骨文会删除什么吗?

在DBZ-137上有一些关于RAC的注释,因为有许多重做线程,所以RAC更加复杂。我不认为RAC在这个范围内。RAC是一个昂贵的选项,只有在负载非常高的大型数据库上才需要它。这更符合Golden Gate的范围。

注意,我们可以解析V$LOGMINER_CONTENTS中的SQL_REDO和SQL_UNDO,但是也可以从dbms_logmnr.mine_value中获取它们

挖掘二进制日志流

有人尝试挖掘二进制重做日志。一些众所周知的商业产品和一些开源尝试。这非常复杂,但对于开放源码社区来说也很有趣。重做日志结构是私有的,但是Oracle不会经常更改它,因为所有可用性特性(恢复、备用……)都基于它。然而,由于这种挖掘暴露了重做的专有格式,因此可能存在一个开放源代码的法律问题。Oracle许可证明确禁止反向工程。

连续查询的通知

我研究了dbms_change_notification作为CDC备选方案的用法:https://blog.dbi-services.com/event-sourcing-cqn-is-not-a-replace -for- CDC。该特性针对几乎静态的数据,以便使缓存失效并刷新。它不是为高变化率而设计的,在这方面一点效率都没有。

客户端结果缓存

与从不经常更改的数据中刷新缓存相同,可以考虑使用客户端结果缓存进行查询,因为当修改发生时,它有一种机制可以使缓存失效。但是,这里的粒度很差,因为对表的任何更改都会使其上的所有查询无效。

物化视图日志

所有更改都可以记录在物化视图日志中。该功能是为物化视图快速刷新而建立的,是一种复制。这与LogMiner使用的重做日志无关。对于物化视图日志,更改存储在表中,必须在使用时删除。但是这个特性存在了很长时间,并且得到了广泛的应用。但是,如果需要重复写入、读取和删除,只是为了将相同的数据放到另一个地方,那么我将严肃地质疑这种体系结构。

触发器

使用触发器,我们可以像使用物化视图日志一样记录更改。它提供了更多的可能性,比如发送更改而不是将其存储在数据库中(但是我们必须管理事务的可见性)。Connor McDonald发布了一个存储经过审计的更改的优化示例:

https://blogs.oracle.com/oraclemagazine/a-fresh-look-at-auditing-row-ch…

但是这仍然是很大的开销,需要在添加或删除列时进行调整。

ORA_ROWSCN

当启用行依赖项时,ORA_ROWSCN伪列可以帮助筛选最近更新的行。然而,这种方法有两个问题。

完全读:如果我们想要一个接近实时的复制,我们可能会频繁地为更改池。如果被索引,ORA_ROWSCN会很好,但事实并非如此。它只读取存储在表块中的信息。这意味着要找到在过去5分钟内完成的更改,我们需要完全扫描表,然后ORA_ROWSCN将帮助识别那些被更改的行。它是“最后更新”列时间戳的透明替代方案,但无助于快速访问这些行。

提交时间:任何读取“更改”时间戳的内容都存在一个普遍问题。假设我每5分钟收集一次变化。我有一个很长的事务,它在12:39更新一行,并在12:42提交。在12:40运行的池,查找12:35以后的更改,由于还没有提交,所以看不到更改。在12:45运行的池可以看到它,但是当它过滤自上次运行(即12:20)以来发生的更改时,就看不到它了。这意味着每次运行都必须查看更大的窗口,包括最长的事务启动时间。然后它必须处理重复项,因为前一次运行已经捕获了一些更改。当没有可用的“提交SCN”时,这是一个普遍的问题。

Userenv (“commitscn”)

在讨论可见性时间(提交SCN)与更改时,有一种没有文档记录的方法可以获得它。使用userenv(' commitscn ')进行插入或更新,这将在事务结束时神奇地返回到表行,以设置提交SCN。它不受支持,而且它只能在事务中调用一次,然后不能在触发器中自动添加。

甲骨文闪回查询

如果我们不想在DML上添加额外的审计,那么重做日志并不是惟一的内部日志记录。Oracle还会记录一致读取的撤消信息(MVCC),并且在不增加修改开销的情况下,可以显示表中发生的所有更改。基本上,我们可以选择…从…版本之间的SCN…和…所有的变化都将是可见的与新的和旧的值和附加的信息有关的操作和事务。

但是,它没有被索引。就像使用ORA_ROWSCN一样,我们需要对表进行全扫描,由于撤消操作,一致的读操作将构建以前版本的块。

闪回数据档案

闪回查询可以重构最近的更改,这些更改受到撤消保留和最近发生的DDL的限制。Flashback数据存档(称为完全回忆)可以更进一步。该特性在企业版中可用,不需要额外的选项。它可以超越撤销保留并允许一些DDL。但是,再次强调,它没有经过优化以获得自特定时间点以来的所有更改。其思想是,当您知道要读取的行时,它就可以转到以前的版本。

 

最小触发+闪回查询

其中一些解决方案可以组合使用。例如,触发器只能记录更改行的ROWID,而复制过程将通过flashback查询获得关于这些行的更多信息。这降低了更改的开销,同时仍然避免了对复制进行全面扫描。或者,您可以直接从定制挖掘重做日志中获得这些ROWID,这比试图从中获取所有信息要简单得多。

DDL触发器

SQL是敏捷的,允许结构更改。如果添加一个列破坏了整个复制,那么就有问题了。上述所有解决方案都需要处理这些更改。重做日志包含字典中的更改,但是解码起来可能很复杂。所有其他解决方案都必须适应这些更改,这意味着要有DDL触发器并处理不同类型的更改。

不容易…

总结一下,没有简单的解决方案,最简单的方案已经被Oracle移除,以推动金门的销售。当有人想要复制更改并从另一个地方查询它时,我的第一个建议是:不要这样做。关系数据库用于获取新的数据和修改,并能够查询不同的目的。我们有以不同格式显示数据的视图。我们有索引来快速访问不同的用例。甲骨文并不像它的许多竞争对手。从第一个版本开始,它就针对混合工作负载进行了优化。您可以查询发生更改的同一个数据库,因为SELECT不会锁定任何内容。您有一个资源管理器来确保失控的查询不会减慢事务活动。如果正确地调优,这些查询的CPU使用率很少会高于将更改流到另一个数据库所需实现的复制活动。

那么,事件源应该建立在哪种技术上呢?LogMiner看起来很适合基本使用的小型数据库。而且该项目应该适应Oracle将来删除的特性。

混合触发器/闪回查询

当只涉及到几个表时,生成DML触发器可能是最简单的,特别是当它们只记录最小值时,比如ROWID。只有在提交事务时,ROWID才可见。然后复制过程必须使用闪回查询,只从ROWID中读取那些块。这里的好处是,flashback查询显示的是更改何时可见(提交时间),而不是更改时间,这使得过滤上次运行时已经处理的更改变得更容易。

这是一个想法,当一个触发器日志的ROWID变成了一个DEMO_CDC表,我们查询:

执行计划显示最佳访问与ROWID:

Explain Plan
------------------------------------------------
PLAN_TABLE_OUTPUT
Plan hash value: 3039832324------------------------------------------------
| Id  | Operation                   | Name     |
------------------------------------------------
|   0 | SELECT STATEMENT            |          |
|   1 |  NESTED LOOPS               |          |
|   2 |   SORT UNIQUE               |          |
|   3 |    TABLE ACCESS FULL        | DEMO_CDC |
|   4 |   TABLE ACCESS BY USER ROWID| DEMO     |
------------------------------------------------

这里重要的一点是,查询成本与更改成比例,而不是与表的完整大小成比例。触发器开销仅限于ROWID。不需要将已经存储在基表和撤消段中的值存储在表中。如果频繁地读取这个数据,那么所涉及的所有块(ROWID列表、UNDO记录和表块)很可能仍然在缓冲区缓存中。

 

原文:https://medium.com/@FranckPachot/ideas-for-event-sourcing-in-oracle-d4e016e90af6

本文:https://pub.intelligentx.net/ideas-event-sourcing-oraclelog-miner-or-are-there-other-alternatives

讨论:请加入知识星球或者小红圈【首席架构师圈】

Article
知识星球
 
微信公众号
 
视频号