放弃XStream吧,聊聊我们怎么用自研的TLA组件搞定Oracle日志解析
放弃XStream吧,聊聊我们怎么用自研的TLA组件搞定Oracle日志解析
先交代一下背景。我们团队一直在做数据库事务日志解析这块的技术,说白了就是CDC(Change Data Capture)最底层的那层——把Oracle的redo log啃下来,解析成业务能理解的数据变更事件。
之前调研过市面上几乎所有方案,LogMiner太慢这个大家都知道,OGG太贵这个大家也知道。后来我们把目标锁定在Oracle XStream上,研究了一圈,踩了不少坑,最终还是决定自己撸一套组件,也就是现在这个TLA(Transaction Log Analysis)。
这篇文章不吹不黑,纯技术层面的记录。把XStream的问题和我们自己实现方案的一些思路写出来,给正在做类似选型的同行们参考。
XStream到底是什么?官方说法和实际情况
看Oracle官方文档,XStream被描述成一套API,允许外部应用直接接入数据库的变更流。它比LogMiner先进的地方在于,LogMiner是等redo log落地成文件后再去读,而XStream在事务提交的时候就能把事件扔到内存的Stream Pool里,外部程序可以直接消费。
听起来很美好对吧?实际用起来是另一回事。
首先最劝退的就是授权问题。
XStream虽然是Oracle数据库自带的,但你要正经用起来搞数据同步,必须要有OGG(Oracle GoldenGate)的License。OGG什么价格?官方标价$17,500 per processor,每年还要交22%的技术支持费。而且前提是你还得有Oracle Database Enterprise Edition的授权。
我们之前给一个客户做方案,他们生产环境16个CPU核心,光是OGG授权算下来就奔着30万美金去了,还不算Oracle EE的钱。老板听完脸色都不太对,这还没开始干活呢,成本已经扛不住了。
其次是数据类型支持,这个真的很要命。
XStream官方文档里写得清清楚楚,不支持ROWID、不支持BFILE、不支持嵌套表、不支持ANY TYPE、不支持URI类型、不支持虚拟列。
你可能觉得这些类型平时用得少,但我们在实际项目里遇到一个场景——客户的业务表里有XMLType列,然后做了一个INSERT带APPEND提示,XStream直接报错。查了一圈官方资料,发现这玩意儿在某些操作组合下就是不行,没有workaround。
还有SecureFiles LOB,要求数据库兼容级别必须是11.2.0.0以上才支持,如果你用的是老版本或者有兼容性限制,这个功能直接废了。
第三是并发模型太死板。
一个XStream出站服务器只能连一个捕获进程,只能服务一个集成任务。如果你有多个下游系统需要消费同一个数据库的变更,就得起多个出站服务器。我们有个用户场景需要同时同步到三个不同目标,就得配三套,资源消耗和运维复杂度直线上升。
而且它内部会缓存未提交的事务,直到commit才发出来。如果碰到一个大事务,几百万行更新没提交,这些数据全攒在内存里,对数据库本身的内存压力很大。我们遇到过因为大事务导致Stream Pool撑爆、整个捕获进程卡死的案例。
第四点,XStream只是API,上层所有东西都要你自己写。
事务一致性你得自己保证吧?检查点和断点续传你得自己实现吧?数据加密、类型转换、异常恢复……这些全要开发。不同的第三方工具基于XStream的实现质量参差不齐,一致性根本没保障。出了问题开SR找Oracle支持,排期、补丁、升级数据库版本,一套流程走下来人都麻了。
我们自己搞的TLA是怎么做的
因为上面这些原因,我们决定自己写一套日志解析组件,取名TLA。目标很明确——替代XStream这套东西,但不受它那些限制。
核心思路其实不复杂:绕过所有中间层,直接解析redo log的二进制格式。
Oracle的redo log再怎么封装,最终就是磁盘上那一堆二进制块。我们直接去读这些块,解析里面的Change Vector,把事务语义还原出来。
这样做的好处是:
- 不需要OGG授权,也不需要Oracle EE,就是个独立的解析组件
- 不在源库内部跑任何进程,可以部署在独立服务器上远程读日志
- 数据类型的支持我们自己控制,不存在XStream那种"这个不支持那个不支持"
V2.0我们做了个重要的架构改进,叫SPSM-ZO Engine。
传统方案(包括XStream)的问题是,解析可以是多线程的,但事务顺序一致性必须在某个环节收敛成单流。这个收敛点就是性能瓶颈,相当于前面跑得再快,到这儿都得排队。
我们的做法是把顺序控制直接做到解析阶段。多线程在解析的同时就按顺序把事务流构建好,后面不需要再排序。这个差异在压测的时候体现得很明显。
直接上我们测的数据
说半天理论,来点实际的。我们自己做了对比测试,贴一下数据供参考。
先说明硬件环境:TLA这边用的机器是32核、64GB内存。对比的Tapdata/FlinkCDC用的是80核、192GB内存。TLA的硬件配置明显低一截,如果同配置跑差距会更大。
小数据量场景(7字段,1120MB数据):
| 产品 | 吞吐量 |
|---|---|
| TLA | 10.8万条/秒 |
| Tapdata | 8万条/秒 |
| FlinkCDC(LogMiner) | 1.2万条/秒 |
FlinkCDC那个1.2万条基本就是LogMiner的上限了,单线程解析硬伤,再怎么调优也就这样。
大数据量场景(50字段,1GB日志):
| 产品 | 耗时 | 吞吐量 |
|---|---|---|
| TLA | 10.6秒 | 97 MB/s |
| Tapdata | 20.5秒 | 50 MB/s |
| 某国产CDC | 41.8秒 | 24.5 MB/s |
| FlinkCDC | 149.6秒 | 6.8 MB/s |
TLA大概是Tapdata的一半耗时,是FlinkCDC的十四分之一。
说一个关键细节:我们测TLA的时候用的是"每行一个COMMIT"的模式,这是最慢的提交方式,事务开销最大。批量提交(多条记录一次COMMIT)是业界常用的优化手段,但我们刻意用了最严苛的模式来测。即使这样数据还是领先,如果改成批量提交,差距会更大。
XStream搞不定的那些类型,我们全部支持
整理了一个表格,XStream不支持的这些,TLA目前都支持:
- ROWID / UROWID
- BFILE
- 嵌套表(Nested Tables)
- ANY TYPE / ANYDATASET
- URI类型
- 虚拟列(Virtual Columns)
- 多字节字符集下的LONG
- XMLType(所有操作场景,不挑)
- SecureFiles LOB(无版本限制)
我们做了但XStream没有的功能
除了基本的DML/DDL捕获,TLA还支持:
表/行/列级别的选择性过滤。 如果你只需要同步特定的几张表,甚至特定条件的数据行,可以在解析层直接过滤掉无关日志,不需要下游再处理。
检查点机制。 每次commit边界都落检查点,进程挂了或者网络断了,从上次检查点续传就行,不丢数据也不重复。
RAC + ASM + CDB/PDB全支持。 这些都是实际生产环境的标配,XStream在PDB场景下配置很麻烦,TLA这边直接连接PDB就能解析,也支持一个CDB里监控多个PDB。
DG备库直接解析。 不用连主库,直接去备库读日志,对生产零影响。
绝境救援模式。 这个算是一个额外能力,如果redo日志文件物理损坏导致数据库起不来,又没有任何备份,TLA可以尝试直接从损坏的日志残块里往回捞数据。绕过文件系统完整性检查,直接读二进制块,能捞多少算多少。这个功能平时用不到,但遇到一次就值回票价。
总结一下
XStream是个有技术想法的产品,但被Oracle的授权策略和生态绑定限制得太死。对于国内大部分项目来说:
- 要么根本用不起(授权费用太高)
- 要么用不全(数据类型限制太多)
- 要么用得不爽(出了问题得等Oracle补丁)
TLA是我们自己从底层一行一行写出来的解析组件,目前在功能对标上完全覆盖XStream的使用场景,还在数据类型支持和部署灵活性上做了不少增强。最核心的是——这东西完全自主可控,不依赖任何第三方商业软件,想怎么改怎么改。
目前Oracle版本已经跑通了,后面MySQL、PostgreSQL和几个主流国产数据库的支持也在推进中。
写这篇文章主要是把踩坑经历和我们的解决思路记录下来,如果同行们也在做类似的技术选型,可以少走一些弯路。有什么问题欢迎留言聊,技术这东西越辩越明。
补充一下:文中提到的测试数据都是我们自己实测和对比产品官网公开数据整理出来的,测试方法写得还算清楚,感兴趣的朋友可以按相同条件自己跑一遍验证。

浙公网安备 33010602011771号