Administrator
发布于 2024-03-20 / 3998 阅读
87

一次核心系统去 Oracle 化的完整过程

去年底老板拍板:核心交易系统去 Oracle。理由很直接——一年 380 万的授权费,加上审计合规越来越严。我接手时第一反应是:这活儿坑比想象多,不是导出 SQL 再导入就完事。

先盘家底

系统跑了九年,Oracle 里不止 SQL。我用了两周做依赖盘点,列了一张表:

依赖类型数量风险
存储过程/函数213 个高,逻辑重
触发器41 个中,行为隐式
序列(Sequence)67 个低,有替代
自定义类型/包28 个高,无直接对应
DBLink 跨库查询9 个中,需改架构

真正难的是那 213 个存储过程和 28 个包,里面有大量业务规则。直接翻译到 MySQL 语法只是第一步,逻辑正确性才是雷区。

兼容性改造:分层拆解

我们没有一把梭全改,而是按"能不能挪到应用层"分层:

  • 能上移的:把 60% 的存储过程逻辑改成 Java 服务里的 Spring 事务方法,用 @Transactional 保证一致性;
  • 必须下沉的:剩余涉及多表批量计算的,用 MySQL 的存储过程重写,但把隐式游标改成显式 CURSOR,并补上异常处理;
  • 触发器:能删的删,不能删的用 Binlog + 下游消费者替代,避免触发器带来的写入放大。

一个典型的 Oracle 分页 ROWNUM 写法:

-- Oracle
SELECT * FROM (SELECT t.*, ROWNUM rn FROM orders t WHERE ...) WHERE rn BETWEEN 21 AND 40;
-- 改 MySQL
SELECT * FROM orders WHERE ... ORDER BY id LIMIT 20 OFFSET 20;

看起来简单,但 ROWNUM 带排序语义的查询,翻译错一次就会分页漏数据。

数据迁移:全量加增量

全量用自研的批导工具,按主键分片并发,单表 8000 万行跑了 6 小时。增量用 Oracle GoldenGate 同步到 MySQL,追平延迟控制在 3 秒内。迁移期间双库同时写,靠应用层双写开关控制。这里最怕的是两边"写后读不一致"——我们在关键读路径加了"以 Oracle 为准"的开关,灰度期全走老库。

双跑验证

上线前做了 30 天双跑:同样一笔请求,应用层同时打 Oracle 和 MySQL,用对账 Job 比结果。初期每天差 300+ 笔,逐一定位,大多是浮点四舍五入、NVLIFNULL 的空值语义差异。修到连续 7 天差异为 0,才敢动切换预案。

切换预案:不成功就回滚

切换按"读流量 → 非核心写 → 核心写"三步走,全程可回滚:

  1. 读流量切到 MySQL,观察 24 小时,监控错误率和延迟;
  2. 非核心写(日志、统计)切 MySQL,保留 Oracle 双写为兜底;
  3. 核心写切换当晚,停 Oracle 写入、保留只读 7 天,确认无误后下线。

真正切核心写那晚,我们准备了 15 分钟回滚窗口:一旦 MySQL 主库报错率超 0.5%,立刻把写开关拨回 Oracle。结果是平稳的,P99 延迟反而从 Oracle 的 23ms 降到 14ms。

组织协同比技术更难

技术之外,去 O 真正的阻力在协作。DBA、业务、测试三方对"双跑差异"的容忍度不同:DBA 要 0 差异才肯切,业务怕影响交易,测试只认自己的用例。我们每周开一次对齐会,把当日差异清单逐条过,明确"哪些差异可解释、哪些必须修"。有次一个浮点差异 DBA 坚持要修,业务说不影响,最后我们加了一层"金额精度统一到分"的兜底转换,两边都签字。这种跨团队的"差异仲裁机制"比任何技术方案都重要——没有它,双跑会无限期拖下去。

留个问题

关于《一次核心系统去 Oracle 化的完整过程》里这个坑,你当时是怎么处理的?欢迎在评论区聊聊你踩过的类似情况。

参考