作者 | 王英杰
策划 | 田晓旭
陆金所从 2018 年启动全站去 O 项目以来,在不做任何服务降级的情况下,历时 2 年通过上百次变更,把全站 98% 的 Oracle 数据库无缝切换到 MySQL 上。其中,这 98% 的数据库覆盖了陆金所的账务、资金、资产中心、支付、交易、用户、基金、主账户、网贷、资管、银行理财等全金融场景。整个去 O 的全程 0 故障、0 风险、对用户几乎不感知。
陆金所去 Oracle 实践有四大特点:
一是在线更换数据库,不做服务降级。让去 O 这类重大架构改造实施落地的时候对全站用户影响最小,同时也最考验去 O 的架构改造的技术实现能力。
二是对于高频上线了上百次的去 O 变更,全程 0 故障、0 风险,这一点非常考验陆金所去 O 的变更工具水平。
三是在短短 24 个月的时间完成全站 98% 的数据库去 O 改造,并且涉及陆金所全部最核心的业务,去 O 的整体落地效率非常快。
四是在去 O 各个环节实现了从开发、测试到运维各种自研智能工具来把控去 O 各个核心环节的质量,这也是把一个庞大、复杂、高风险的金融核心系统,在非常短的时间内 0 风险、0 故障,稳妥落地去 O 的关键。
陆金所为什么需要启动去全站去 O,并且是 100% 全部去 O。
在去 O 项目立项之初,我们希望通过去 O 来实现三个方面的提升。
首先是降低昂贵的金融系统数据库运营成本。2013 年至 2018 年期间,陆金所的业务成长了上百倍。业务量增长带来的数据库运营成本暴增。无论是传统的 IOE 架构还是去 IE 后的 X86+Oracle 分布式架构都是如此。IOE 架构下,高端服务器和高端存储的价格随着提供的计算和 IO 能力呈现指数型增长。X86+Oracle 架构下,分布式改造和数据库细粒度水平拆分后虽然没有 I 和 E 的成本,但数据库节点暴增后导致 Oracle 软件授权费用暴增。
其次是希望通过去 O 来打造一个不依赖特定数据库特性的金融交易系统,彻底摆脱被商业数据库厂商技术绑架的风险。传统金融交易系统使用数据库特性承担了大量的业务逻辑和架构属性,造成系统对某个数据库特性的强依赖,也大大增加了被技术绑架的风险。陆金所通过全站去 O 实现了把金融交易系统里数据库的角色转化为只支持基本增、删、改、查的存储引擎,全站系统架构弱依赖数据库特性。
最后一点也是最重要的一点,我们希望通过全站去 O 这样一个涉及到开发、测试、架构、DBA 等全部研发团队都参与的重大架构改造项目,来锻炼研发队伍、提升研发能力,并把历史上一些架构设计不完善的地方,通过全站去 O 进行重构。因为去 O 不仅仅是更换数据库,更重要的是落地架构拆分、微服务化、分布式事务等配套的大量架构改造工作。这些工作需要开发、架构、测试、运维高度协同配合,并稳妥落地。所以去 O 是非常考验研发团队技术水平的架构改造项目。通过,我们也希望通过去 O 打造“研发规范——研发工具——研发人员”的研发管理体系闭环。这一块我们在后面会详细展开,并向大家进行介绍。
决定去 Oracle 之后,选择什么数据库或存储引擎来承载 Oracle 的流量?我们从功能、资源、案例和压测四个方面来进行选型和评估。
首先,选择的数据库要从功能和性能上能够承接 Oracle 在各种场景下计算和 IO 能力。其次,它还要具备最广泛的社区资源、技术资料和问题处理案例,通俗的说就是大量坑被踩过,以及最广泛的用户基础,外面招开发和运维工程师都比较好招。然后,还要在业界有可参考的金融场景案例。这一点相信大家都很熟悉,阿里和腾讯在金融场景上已经有不少成功的案例。
最后,同时也是最重要的一个评估标准就是陆金所自身上线前严格的压测环节。陆金所在切换任何一张表流量的时候,都会使用生产环境完全真实的数据搭建 O 和 M 并行压测环境,来获取访问这张表的所有读写接口的在 Oracle11.2 和 MySQL5.7 下的性能比对报告。经过每一轮非常严格的压测后,发现 MySQL5.7 的性能比我们预估中的更好。通过从边缘系统往核心系统的逐步去 O 演进中,MySQL5.7 就成为陆金所去 O 最主要的替代存储引擎。
我们都知道 Oracle 是个非常优秀、且覆盖场景非常全面,无论是 OLTP 还是 OLAP 场景表现都很优秀,所以这种功能承接应该远远不止一种数据库或存储引擎,涉及到多种存储引擎发挥他们的优势在各种特定场景下来替换 Oracle。
所以最终的结论是综合选型下来确定 使用 MySQL 为主,TiDB、Redis、ES、HBase 等多种存储引擎为辅的方式,100% 全部替换掉 Oracle。
接下来,我们就详细介绍陆金所的去 Oracle 方案。
陆金所去 Oracle 改造主要是分为应用和数据库两个部分来落地的。
首先介绍一下应用层部分的落地。应用层在去 O 的时候会做一个整体规划,把一个大的系统或库拆分成多个可独立落地的批次,然后会把应用的业务逻辑层从数据库的访问接口尽可能剥离出来,让 DAL 层专注只做好数据库交互的操作。同时,在 Oracle DAL 层的基础上,对 MySQL DAL 层的进行重构,并且配置流量开关让上层的业务逻辑层可以自由选择和数据库的交互是走 Oracle DAL 层还是 MySQL DAL 层。每个批次都会有自己单独的流量开关进行控制。批次拆分的时候遵循一个原则就是把具备业务相关性和事务相关性的表放在一个批次里。
再说数据库层的落地,在 Oracle 还在不断对外提供服务的时候,我们会在后台建立起一个和 Oracle 保持实时数据同步的 MySQL 数据库,即当 Oracle 的事务提交后,秒级同步到后端的 MySQL 里面。同时这个同步是双向的,当未来流量切换到 MySQL 后,也会在 MySQL 事务提交完成后,把数据秒级同步回 Oracle,这就类似 MySQL 的双 master 架构,只不过数据是在 Oracle 和 MySQL 这个异构数据库之间建立双 master 架构。
在这个架构中为了确保数据库的一致性和完整性,一定是严格要求某个批次的写流量只能在某个时间点只能在 O 和 M 一个地方写入。陆金所研发了一整套自动化构建数据库双写的工具平台,只要在平台上选择需要建立批次的 Oracle 表,就能在后台全自动完成 Oracle to MySQL 从表结构转化、数据全量同步、数据增量同步、数据实时同步、数据校验和数据双向同步建立整个全流程繁琐。依据这套自动化平台,陆金所只投入 2 个 DBA 就完成了全站上万张表的去 O 数据库迁移和运维层的全部准备工作。
最后是流量切换,我们设计并研发了一套总控开关机制来协调从应用、到数据库、到传输、最后到流向的全盘流量切换。实现当流量在 O 时,实时同步到 M。当流量在 M 时,实时同步到 O。保证切换一瞬间,最后一笔事务在源库提交成功,在目标库传输成功,并完成最后一笔事务的数据在源库和目标库的数据校验后,同一个批次下所有表的写流量在同一个时间点同时完成切换。
虽然去 O 流量切换会在 10 秒内瞬间完成,但整个过程按照细粒度划分会有十多个步骤。为了方便介绍,我们把这十几个步骤精简成了三个状态。
首先是初始状态,这个状态下生产的只读流量可以在 Oracle 或 MySQL,写流量可以在 Oracle,由 Oracle 对外提供服务。这个状态状态可以理解为 Oracle 为主库,MySQL 为 Oracle 的异构实时备库。
其次是中间状态,这个状态下 Oracle 和 MySQL 会进入一个非常短暂的写保护静止状态。在完成最后一笔 Oracle 事务提供成功,并同步至 MySQL,且完成最后一笔数据一致性校验后,会把应用开关的流量切换到 MySQL,这个时候这个批次的写流量在某个时间点全部一致性都切换到 MySQL。
一旦在 MySQL 里写流量进来,就进入了第三个状态即完成状态,一旦写流量的事务在 MySQL 中提交成功,双向实时同步链路会把 MySQL 的数据秒级同步回 Oracle,这个时候可以理解为 MySQL 是主库,Oracle 是 MySQL 的实时备库。
需要注意的是,这个架构下需要解决大量的细节问题,比如避免同一笔记录双向循环写的问题。
陆金所实现的这个双写框架流量切换速度极快,在数秒内就能实现有状态的写流量从 O 到 M 的快速切换,整个过程在低峰期落地对业务影响非常小,甚至是不感知。如果在去 O 之前在 Oracle 内部已经完成了对用户的水平拆分,以批次和用户双重细粒度进行去 O 流量切换,那么整个更换数据库过程几乎是无感的。
在流量从 O 切换到 M 后,以陆金所落地的经验来看,大概有一定概率(比如程序的 bug)需要回切到回 Oracle。这套切换框架可以确保在几秒内流量快速回到 Oracle,且在 MySQL 写入的少量数据也会同步会 Oracle,且在保证 Oracle 和 MySQL 两边的数据严格一致性和完整性的过程中,进行流量的快速前滚和回滚。
了解了去 O 流量切换的架构和方案,接下来我们介绍如何在一个关联系统庞大、业务逻辑复杂、改造风险极高的金融核心系统里落地整个去 O 方案。
首先我们会以表为粒度来把一个复杂、庞大的金融核心系统和数据库拆分成多个批次,拆分的原则上面也提到了一点,即把有业务相关性和事务相关性的表放在同一个批次里,在确保这个基本原则的情况下,把单个大库尽可能的拆分成多个批次,确保每个批次里的表尽可能的少。
为什么要基于这个原则来落地实施呢,因为批次是去 O 变更的单位,O 和 M 之间的流量切换开关是控制到批次的。把批次拆分的足够细,最终目标是为了实现“改造难度可控、上线进度可控、切换风险可控”的 3 原则。
首先对于金融核心系统中一个复杂的模块来说,去 O 改造的周期会横跨半年甚至一年以上,在这个过程中,金融核心系统在 7*24 小时不间断对外提供服务,应用层的代码和功能每个月甚至是每周也处在高速迭代中,不断的新功能被加入到系统并被发布到生产。
而在这个过程中,要落地去 O 这类庞大的架构改造,必须框定一个可快速迭代和实施的改造范围,批次就是一个合理设定的单次去 O 改造和变更的范围。批次拆分的粒度细,可以确保在单个批次的去 O 改造工作量可控、改造难度也可控。
同时因为批次的粒度细,在做去 O 变更切换流量时,对整个金融核心系统的影响也可控。基于这种思路,就可以实现“小步快跑”的高速迭代方式来改造应用、上线版本以及切换流量。即每次只改动核心系统的一小部分,改动完成后快速测试、快速发版上线、并且风险可控的把这部分流量切换到 MySQL 运行,如果有问题依靠强大的流量切换框架,快速把流量回切回 Oracle。
从图中大家可以看到一个庞大的金融核心系统去 O 改造中,应用改造、上线版本和流量切换这 3 件事情实在并行落地的。
最开始是应用改造,改造完了上线发版,发版后就有了这个批次 O 和 M 的流量开关,并具备了切换条件,之后在某个变更日把流量从 O 切换到 M,如果遇到任何问题可以快速切回来。应用版本在不断上线迭代,流量在分批次不断切换,一个庞大的金融核心系统就在多次高速迭代中一点点的从 O 切换到了 M。
整个过程对核心业务不影响、不感知,且对参与去 O 的开发、测试和运维开展去 O 工作非常友好,让他们可控的去落地各项工作。
在这个过程中,从第 1 张表从 Oracle 切换到 MySQL,到最后一张表关闭 Oracle 流量,在非常长的一段时间内,整个应用是由 Oracle 和 MySQL 在同时提供服务。其中某些表已经完成去 O,读写的流量在 MySQL 上,由 MySQL 同步到 Oracle,部分表还未完成去 O,读写流量在 Oracle 上,由 Oracle 同步至 MySQL。这就非常考验运维的能力,要确保在这个架构下每天高频的各种发版和数据库变更都非常准确。
基于此,陆金所是有研发一整套配套去 O 变更工具,来确保整个去 O 过程中大量变更准确实施和落地。以陆金所交易、主账户、资产中心、基金、账务等核心库为例,从第一张表流量切换到 MySQL 到最后一张表切换到 MySQL,历时 12 个月以上。按照上述方案一点一点的替换掉 Oracle 数据库,整个过程完全不做服务降级,对陆金所的 4500 多万用户无感知。
在 PPT 中画出去 Oracle 的架构图是很简单的事情,但是架构改造的难点和重点在于落地。要在生产环境落地是非常庞大且复杂的系统工程,尤其是对一个 7*24 小时的金融核心系统来说,进行重大架构改造本身就是一件高风险的工作,既要做到规避风险,确保各种工程实现细节有效落地,同时又要保证系统的业务连续性,甚至是对外部用户不感知。
去 Oracle 架构改造的本质是什么?我觉得有两方面,一是细节规则,二是上生产前发现和上生产后兜底。
去 O 的重点不仅仅是方案本身,更重要的是组成方案的数百条细节规则,能在一个参与去 O 的、庞大的研发团队里每个开发所写的每一行代码都有效遵守规则,同时在每个运维设计的生产变更方案里每一条命令都有效遵守规则。方案通过从边缘系统往核心系统逐步推进过程中,会逐步趋于完善,方案中的规则也会被逐步积累和完善起来,那么把这些规则落地到研发团队的每个人上,是关键和重点。
上生产前发现是指如果规则在某个微小的细节实施时没有被遵守,如何尽可能的在上生产环境之间发现隐患。上生产后兜底如果问题突破了所有检测环节上了生产,如何设计一个兜底方案可以有效控制风险,把影响尽可能降低。
去 Oracle 落地工作都应该围绕有效解决这两个本质问题展开,并提升这两个问题的解决效率,降低人力成本。
陆金所的做法是建立“人员——规则——工具”的闭环。
陆金所通过“人员制定规则——规则通过工具落地——工具确保所有人员的代码和变更符合规则”的方式来确保各种细节工作落实到位,整套工具最终沉淀为陆金所数据库升级平台。
以陆金所的去 O 落地经验来看,一个不起眼的细节问题如果未进行有效管控,都有可能引发严重的生产故障。所以我们可以把陆金所数据库升级平台理解成为一套强大的去 O 风控系统。这套风控系统覆盖 SQL 重构、表结构转化、数据迁移、数据校验、分布式事务构建、流量切换等横跨从开发到运维在去 O 架构改造方方面面会遇到的问题。通过这套工具平台,有效确保参与去 O 的研发团队在每个细节上都处理的非常规范,从而实现历时 24 个月的全站去 O,无风险平稳落地。
除了确保各种规则精准落地外,金融核心系统去 O 改造需要多个研发团队协同作战、有效配合、共同推进。其中涉及到大量工程实现细节工作需要多团队有条不紊、事无巨细的协同配合好。任何疏漏都有可能会引发严重的生产故障。
去 Oracle 的口号喊了很久了,但是为什么要去 Oracle,去 Oracle 想要达到什么样的目标...... 有些企业可能没有想得很清楚,所以我也想从自己的角度和经历来谈谈去 Oracle 的目标。
去 O 完成后,使用“免费的开源数据库 + X86 架构的 PC Server”来搭建金融核心系统,真的很省钱。因为搭建金融核心系统从昂贵的高端服务器、高端存储和 Oracle 一体机,以及昂贵的 Oracle 软件授权变成只需要 6 万一台的 X86 服务器,花在数据库上的运营成本降为之前的 10% 不到。
在整个去 Oracle 的过程中,陆金所架构从一个传统金融的超大型数据库支持各种核心业务的架构变成了以微服务化驱动的分布式架构,这种架构具备以下特点:
每个服务有自己独立的应用和数据库。
每个库只提供给服务内的应用直接访问,即服务内的应用可以通过 SQL 访问。
服务之外的应用访问数据库需要走应用层的服务接口,避免跨服务访问数据库。
服务分为同步调用和异步消息。
在服务内实现数据库的水平扩展。
对于类似用户、交易、资金等公共类基础服务,逐步迭代为中台服务。
通过微服务化拆分,几套集中式的 IOE 大库就变成了微服务小库,同时对于访问量和数据量较大的中台服务,又会进一步细粒度水平拆分。
除了降低成本,我认为更重要的是通过去 O 实现传统金融系统全方位的架构升级和改造。
对于一个传统金融系统来说,借助去 O 来实施和落地全系统的架构改造和升级,应该是一个再好不过的机会。以陆金所为例,通过去 O 实现了以下的升级和改造:
数据库底层计算和 IO 能力的水平扩展,并且这种水平扩展完全基于 6 万一台的 X86 服务器,扩容成本极低。
同时实现了应用访问数据库的规范化,应用和应用之间的服务化。全站的调用链会非常清晰,应用和数据库之间不合理的依赖将大幅降低。
另外实现数据库层去中心化,单个数据库的可用率对全局可用率影响有限,消除中心化的单点隐患
最后借助去 O 实现的分布式架构,可以把各个分片的数据库部署在不同的机房,从而实现真正意义上的机房多活。
提到去 Oracle,可能很多人在第一时间就想到了 MySQL。其实,MySQL 是承接 Oracle 主要流量的数据库,但 MySQL 无法承接 Oracle 的全部流量,例如以下几类经典场景:
Oracle 在 oltp 场景当中少量 hash join 查询场景。
Oracle 中多表关联和多层复杂嵌套查询场景。
MySQL 细粒度拆分后,跨库、跨分片的查询场景。
在 MySQL 集群和 Hadoop 集群之间构建一个秒级数据同步的 ODS 层。
在这些场景中,可以引入 TiDB、Elasticsearch、Impala+kudu、Redis 等多种存储引擎。这些存储引擎在合适的场景下替换 Oracle,产生的效果是不但比 IOE 架构成本低得多,性能也会比 Oracle 快得多。
我们以 TiDB 为例来讲讲使用 MySQL 之外的存储引擎是如何支撑 Oracle 流量的。
陆金所有个实时对账的场景,需要跨用户库、交易库、资金库和资产库进行复杂的关联查询。在完成去 O 后,数据库在 MySQL 上做了细粒度拆分,无法跨多个独立的服务库进行复杂且高频的跨库查询。
为了支持这个场景,我们研发了数据总线来实施解析 MySQL binlog 并生成消息同步至 TiDB,事务在 MySQL 提交后实现秒级同步至 TiDB。之后通过 TiDB4.0 的 TiFlash 功能(类似 clickhouse 的列式存储),在 MySQL 和 Hadoop 之间搭建一个实时 ODS,实现了秒级处理跨库、多表、复杂关联的查询场景。性能远超去 O 之前在 IOE 架构下的处理结果。
更多实践细节,可以参考 InfoQ 公开课的视频回放
https://www.infoq.cn/video/NAje834UlKY75bXVjMCN
InfoQ 读者交流群上线啦!各位小伙伴可以扫描下方二维码,添加 InfoQ 小助手,回复关键字“进群”申请入群。大家可以和 InfoQ 读者一起畅所欲言,和编辑们零距离接触,超值的技术礼包等你领取,还有超值活动等你参加,快来加入我们吧!
点个在看少个 bug 👇