写点什么

数据库表结构变更处理方案

  • 2020-02-14
  • 本文字数:2730 字

    阅读完需:约 9 分钟

数据库表结构变更处理方案

导读:DBus 是我们要介绍的在敏捷大数据(Agile BigData)背景下的第一个平台。企业中大量业务数据保存在各个业务系统数据库中,为同时解决数据同步的一致性和实时性问题,DBus(数据总线)平台应运而生。DBus 专注于数据的实时采集和实时分发,是一种基于日志的解决方案,同时能够提供消息订阅的方式给下游系统使用。本篇文章主要介绍在 DBus 的设计中,它是如何处理表结构变更及其带来的各种问题的。


数据库表结构变更在软件产品快速迭代过程中是普遍存在的现象,抽取数据库中的数据是 DBus 最重要的功能之一,那么对于数据库中表结构变更及其带来的各种问题,DBus 是如何处理的呢? (本文仅讨论 DBus for Oracle 的实现方案)


贴源输出是 DBus 的基本设计原则之一,通过解析后的数据库日志获取数据转换成 UMS 输出到 Kafka,当表结构发生变更时 DBus 必须能够及时的调整输出 UMS 的结构,以确保和数据库中表结构保持一致,这里有两个问题需要解决:


  1. 如何感知表结构变更?

  2. 表结构变更后,新的表结构要如何与 OGG 输出的二进制数据关联?


一、感知表结构变更


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


(1)RPC 方案


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


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


(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 存储过程的方案。这里要感谢韩锋老师对我们的帮助(韩锋:DBAplus 社群原创专家,现任宜信技术研 发中心数据库架构师。有着多年的一线数据库架构、设计、开发经验,精通多种关系型数据库,实践经验丰富,著有《SQL 优化最佳实践》一书),韩老师在听了我 们的实现原理之后,启发我们自治事务应该可以解决这个问题,我们即刻动手开始改造 DDL trigger,使之支持自治事务,经过改造之后该方案才算完美,最终实现逻辑如图 1 所示:


1530511157273053341.png


二、处理表结构变更事件


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


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


1530511171880045720.png


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


1530511188190019121.png


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


A. 只包含 all_tab_cols 视图中的数据


B.既包含 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 之间的数据,如果两次表结构变更是不兼容的,那么必然会导致解析失败。


感知表结构变更以及处理表结构变更事件的最终目的是能够生成正确的输出结果,其中的更多细节以及实现可以参考:


https://github.com/BriData/DBus


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/153


2020-02-14 10:401584

评论

发布
暂无评论
发现更多内容

React数字滚动组件 numbers-scroll

观纵科技

JavaScript 前端监控 React

【网络安全必备知识】本地提权漏洞分析

网络安全学海

黑客 网络安全 信息安全 渗透测试 漏洞挖掘

企业如何构建内部开发者平台?

SEAL安全

IdP 平台工程 企业号 3 月 PK 榜 内部开发者平台

科技助力金融转型 阿里云联合中国信通院在京举办未来金融思享会

阿里云云效

DevOps 数字化转型 金融 BizDevOps 业技融合

3D摄影棚布光工具Set A Light 3D Studio

Rose

Mac软件 Set A Light 3D Studio 3D摄影棚布光工具

Polygon马蹄链质押DApp开发合约部署案例

薇電13242772558

智能合约 dapp

从稀疏表征出发、召回方向的前沿探索

百度Geek说

召回 预训练模型 稀疏矩阵 企业号 3 月 PK 榜

Matlab常用图像处理命令108例(四)

timerring

图像处理

从零开始搭建一个通用的业务技术架构,这套架构 有点牛逼!

程序知音

Java 程序员 编程语言 后端

URule规则引擎

知了一笑

规则引擎 java

真的有那么丝滑吗?面试阿里(Java岗)从投简历到面试再到入职

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

OpenHarmony NAPI 类对象导出及其生命周期管理(上)

离北况归

OpenHarmony

OpenHarmony编译固件新增支持Ubuntu22.04平台

离北况归

OpenHarmony

OpenHarmony内核学习[1]--单独编译OpenHarmony标准系统内核

离北况归

OpenHarmony

@所有人,优秀前端都应该具备的开发好习惯

引迈信息

前端 低代码 开发

PyTorch深度学习实战 | 深度学习框架(PyTorch)

TiAmo

深度学习 PyTorch

非侵入式入侵 —— Web缓存污染与请求走私

vivo互联网技术

CDN

DockQuery | 基于E-R图的数据建模功能使用实践

BinTools图尔兹

数据建模 信创 #数据库

极客时间运维进阶训练营第十二周作业

Starry

NineData x 阿里云 正式上线

NineData

数据库 阿里云 数据迁移 数据管理 NineData

使用Assembly打包和部署Spring Boot工程

做梦都在改BUG

Java spring Spring Boot assembly 框架

OpenHarmony NAPI 类对象导出及其生命周期管理(下)

离北况归

OpenHarmony

如何规避MyBatis使用过程中带来的全表更新风险

京东科技开发者

数据库 mybatis 代码 代码规范 企业号 3 月 PK 榜

被问了n遍怎么把FB视频无水印下载到手机相册!现在双手奉上教程!

frank

facebook #Facebook

图解Redis,谈谈Redis的持久化,RDB快照与AOF日志

小小怪下士

Java redis 程序员 后端

Blazor在IoT领域的前端实践 @.NET开发者日

MASA技术团队

.net blazor MASA MAUI

可插拔组件设计机制—SPI

京东科技开发者

spi Java】 JavaSPI 企业号 3 月 PK 榜

京东小程序CI工具实践

京东科技开发者

小程序 ci 开发 代码 企业号 3 月 PK 榜

一天吃透MySQL锁面试八股文

程序员大彬

MySQL 面试

开源的未来:启动 Open100

开源雨林

社区 开源软件 商业化

8年服务百万客户,这家SaaS公司是懂云原生的

科技热闻

数据库表结构变更处理方案_架构_张玉峰_InfoQ精选文章