千家信息网

DBus数据库表结构变更处理方法是什么

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,这篇文章主要讲解了"DBus数据库表结构变更处理方法是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"DBus数据库表结构变更处理方法是什么"吧!一
千家信息网最后更新 2024年11月27日DBus数据库表结构变更处理方法是什么

这篇文章主要讲解了"DBus数据库表结构变更处理方法是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"DBus数据库表结构变更处理方法是什么"吧!

一、感知表结构变更

对于感知表结构变更,Oracle已经通过DDL trigger为我们提供了很好的支持,接下来我们要考虑的是如何让DBus感知到表结构变更? 我们讨论出以下两种方案:

1.1 RPC方案

在DDL trigger中调用DBus提供的REST服务,将表结构变更事件发送给DBus。

该方案思路简单容易实现,但也有一些明显的弊端,比如DBus需要提供高可用、低延时的REST服务,否则可能会使数据库中的DDL操作变得缓慢甚至执行出现错误; DBus 的REST服务器对有数据实时同步需求的所有数据库都必须开通防火墙策略,这将给DBus的部署带来很大的麻烦。

1.2 OGG实时同步方案

在DDL trigger中将表结构变更事件存储到一张Event表里,然后通过OGG实时的从日志中将数据同步到Kafka,从而感知表结构变更事件。

该方案实现相对复杂但具有很多优点,比如对数据库的侵入性相对较小,DDL执行时只是将数据写入到Event表中,相对网络通信来说,其延时更低、可靠性更高;更明显的优势是这种方案基于数据库日志实现,能够使用Event表的数据,严格的将表结构变更前后的数据区分开。

举例来说,对于表:test来说,依次执行insert → alter → insert 三个操作,因为OGG读取数据库日志存在延时,如果利用RPC方案,可能出现这样的一种情况:DBus REST服务接收到alter事件之后,第一个insert的记录才被OGG捕获并发送给DBus,此时DBus会认为这条数据中包含alter变化后的数据。这是一个很严重的问题,而OGG实时同步方案无论数据还是时间均通过OGG读取日志的方案实现,可以完美的避免这种问题的发生。

对比两种方案OGG实时同步方案优势明显,最终我们采用此方案。

然而,采用这种方案也并非一帆风顺,按照该方案的总体思路实现以后,我们遇到了一个很奇怪的问题:通过DDL trigger写到Event表中的数据无法被OGG读取,在经历多番尝试无解之后,我们试图到OGG的文档中寻找答案,而最终的结果却是:DML or DDL operations performed from within a DDL trigger are not captured.

这个答案让问题变得更棘手,但这是最佳方案,我们没有理由放弃。于是我们开始尝试在DDL trigger中调用存储过程,在存储过程中执行Event表的insert操作,但由于存储过程和DDL trigger仍然属于同一个事务,因此Event表的数据依然不能被OGG捕获,但通过这个尝试我们觉得只要在另外一个事务中写Event表就能解决我们面临的问题,于是我们又想到了RPC,但RPC缺点太过明显。那么有没有其他可以替代的方案呢?

实际上oracle数据库里可以使用多种语言来编写存储过程,Oracle 8i开始支持java编写存储过程,于是我们立即开始实现java存储过程,通过JDBC连接数据库实现Event表的写入并提交事务,最终通过实践验证了这种办法的可行性,OGG成功的获取到了DDL trigger调用java存储过程写入到Event表的数据。

然而,这种实现并不算完美。当我们在生产环境部署DDL trigger的时候,发现数据库服务器中并没有安装执行java所需要的组件,每次部署都需要DBA同学安装执行java存储过程所需要的组件,我们试图找到一个不使用java存储过程的方案。这里要感谢韩锋老师对我们的帮助,韩老师在听了我 们的实现原理之后,启发我们自治事务应该可以解决这个问题,我们即刻动手开始改造DDL trigger,使之支持自治事务,经过改造之后该方案才算完美,最终实现逻辑如图1所示:

二、处理表结构变更事件

DBus已经具备通过事件方式感知表结构变更的能力,接下来详细说明一下表结构变更事件该如何处理。

下图描述了Event的完整处理流程:

Event中描述了发生结构变更的表名、该表所属的schema以及元数据版本号,DBus接受并解析Event之后,根据表名、schema以及版本号调用元数据抓取模块获取该表的元数据(包括表的字段类型、长度以及注释等)信息,实际上DDL trigger和alter语句在一个事务中执行,这样在trigger执行过程中无法从oracle的数据字典里获取到修改之后表结构元数据,我们写入到meta_history表中的元数据只是执行alter语句之前的元数据信息(因此我们给这个表取名为table_meta_his),要得到完整的元数据信息需要联合table_meta_his和数据字典进行查询,示意SQL如下:

这个SQL的结果有两种可能:

1)只包含all_tab_cols视图中的数据

2)既包含all_tab_cols视图中的数据又包含table_meta_his表的数据(is_current字段的作用是区别该字段的来源)

结果A表明在table_meta_his表中没有找到数据,这说明在生成表结构变更Event至元数据抓取程序成功获取元数据期间没有再次发生表结构变更,结果B则说明在此期间又发生过一次或多次表结构变更。

为什么要使用union all?

单独使用上图中的两个SQL可能导致元数据获取程序获取到错误的结果,例如:接到表结构变更Event 1后,我们调用SQL 1 查询table_meta_his结果集为空,在调用SQL 2之前表结构再次发生变更(命名为Event 2),这种情况下我们通过SQL 2 查询到的结果实际上是再次变更后的结果,使用这个结果产生的元数据去解析Event 1和Event 2之间的数据,如果两次表结构变更是不兼容的,那么必然会导致解析失败。

感谢各位的阅读,以上就是"DBus数据库表结构变更处理方法是什么"的内容了,经过本文的学习后,相信大家对DBus数据库表结构变更处理方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0