
作者|卢文豪,百丽时尚数据库负责人
百丽时尚集团(以下简称百丽)是中国领先的大型时尚鞋服集团,旗下拥有 20+ 个鞋服品牌,如 BELLE(百丽)、TATA(他她)、TEENMIX(天美意)等,覆盖了从高端到大众时尚、功能、运动、潮流等品类,线下门店共计 8000+,覆盖 300+城市。作为中国时尚鞋履市场占有率连续十余年位居第一的企业,百丽拥有发达的线下销售网络,从原料到设计到生产,再到终端零售,已形成产供销一体的完整供应链。
在这条供应链背后,由集团的科技中心统筹业务系统的建设与运维,包括零售、库存、财务等核心板块。为了解除底层技术瓶颈对业务发展的影响,科技中心不断迭代技术方案。其中作为核心之一的财务系统刚刚经历了一场“换心脏”手术,将数据库方案从分库分表 MyCat 架构迁移到 OceanBase,实现了提性能和降成本的“双丰收”。
先说成果:性能提升 30 倍,降本高达原架构的 18 倍,关键功能效率提升 30 倍。
以财务系统的成本核算功能为例,整体运行时间相对较长。原本在 MyCat 运行时需耗时 10 小时,迁移至 OceanBase 后仅需 20 分钟,性能提升 30 倍。由监控数据(见图 1)可以看出,原系统在每日 02:00–12:00 期间磁盘持续高负载;而在 OceanBase 环境下,相同任务 20 分钟内即可完成,负载迅速回落,提效幅度显著,已得到研发团队的高度认可。
图 1 数据库迁移前后性能监控数据
存储成本降 96.7%,硬件成本降 59.4%
原来的 MyCat 数据共占用 20.3 TB,迁移至 OceanBase 后仅占用 1.3 TB,整体压缩率高达 96.7%。压缩收益主要来自两方面:一方面是 OceanBase 自身的高压缩率,另一方面是原来的 MyCat 架构下存在大量数据冗余,经过 OceanBase 的存算一体化架构整合,冗余数据得到释放。
另外,原来的 MyCat 环境部署共使用 37 台服务器,迁移到 OceanBase 后仅用 10 台服务器即可支撑全部业务,使该业务服务器费用从 207 万缩减为 84 万,硬件成本下降 59.4%。
之所以能够取得这样的效果,一方面是由于原架构的冗余与性能瓶颈对业务系统产生了限制,而新的数据库方案不仅解开了瓶颈,还带来了更大的增益。另一方面,归结于正确的迁移和技术优化,下文展开叙述我们的迁移经验。
经验汇总:MyCat 切换 OceanBase 三步走
切换背景
百丽的业务系统原本统一采用 MyCat 中间件实现分库分表,以每个大区(如华南、华北)规划分片粒度,确保了绝大多数门店级库存操作收敛到单分片执行,从而显著减少分布式事务。
图 2 是业务原来基于 MyCat 的 sharding 架构,采用一主两从的配置,主机房位于北京,两个从节点位于乌兰察布机房作为异地容灾机房。业务数据根据地区划分不同的大区分片,每个地区数据访问经由 MyCat 下发到各大区分片执行,为了避免分布式事务,业务层面尽量保证每次获取的数据都只定位到其中某个大区。
图 2 基于 MyCat 的 sharding 架构
在业务的演进过程中,业务数据和业务需求随之增多,分库分表 MyCat 架构逐渐暴露出三类主要问题。
第一类问题是数据迁移困难。当业务需要合并或调整大区时,必须进行跨库数据搬迁。整个过程脚本复杂、回滚窗口小,风险高、周期长。
第二类问题是 MyCat 功能缺陷影响业务。MyCat 仅提供基础路由能力,对复杂 SQL(多表关联、子查询、聚合统计)和分布式事务支持有限,因财务等模块的查询较为复杂,被迫将分片表改为全局表,且需要应用适配,导致数据冗余并增加维护成本。
第三类问题是扩展性差。横向扩容需要重新划分大区并再次触发全量数据迁移,当出现性能瓶颈时,只能依赖垂直升配硬件,无法通过水平扩展快速解决。
为替代 MyCat 并解决其固有痛点,科技中心将选型范围锁定于原生分布式数据库,并明确两项核心诉求:一是高可用,零数据丢失;二是在线弹性扩展,无需停服或搬迁数据。
经过市场调研和多轮评估,百丽科技中心最终选定 OceanBase。下文将以财务核心系统从 MyCat 升级至 OceanBase 的项目为例,系统梳理数据库替换过程中的关键实践。无论采用哪一种替换方案,均需围绕三个核心步骤展开。
1. 数据流转:梳理全链路数据流,明确数据从哪里来、到哪里去。
2. 数据校验:确保数据正确性,验证准确性和一致性。
3. 兼容与调优:识别兼容、性能问题,并治理。
第一步:数据流转
MyCat 架构下
上游数据同步链路如图三所示。
主数据 MySQL:通过 MyCat 以全局表方式向各大区 DB 下发集团各业务通用数据。
财务应用:其他业务系统也会将数据同步到 MyCat,因为不同业务对应的分区是相同的,所以不同业务间的数据同步是通过 DB 一一对应的方式进行。
同步工具:红色链路代表数据同步链路,统一采用阿里开源工具 Otter。
图 3 MyCat 架构下,上游数据同步链路
下游数据同步链路如图 4 所示。
数仓:通过 Binlog 抽取实现入仓。
Oracle:财务系统的业务数据需同步到 Oracle 进行报表分析。
同步工具:红色链路代表数据同步链路,统一采用阿里开源工具 Otter。
图 4 MyCat 架构下,下游数据同步链路
OceanBase 架构下
如果使用 OceanBase 替换 MyCat,上线后能否打通现有数据链路正常流转呢?
上游(见图 5)以 OceanBase 作为目标端的链路实现比较简单,只需修改目标端配置即可实现数据同步,可以维持旧方式进行同步。
图 5 OceanBase 架构下,上游数据同步链路
相对上游,下游的替换比较复杂。之前 MyCat 架构下是基于 Binlog 实现的数据同步,如果替换为 OceanBase,无法直接提供 Binlog 日志以供下游消费。那么如何同步数据到下游呢?有两种解决方案(见图 3)。
第一种方案:在 FasOceanBase 部署 OceanBase Binlog Service 来生成 Binlog,对整个数据链路来说,基本可以通过 Otter 跑通整个链路,兼容性是最好的,改动最小。但也存在一些问题,比如 MyCat 中有八个 MySQL 分片,相当于 8 个线程去采集 8 个数据库实例的数据。由于 OceanBase Binlog Service 是以租户为维度,无论是生产 Binlog 还是消费 Binlog,都只能有 1 个线程去处理。在业务高峰期间, 可能存在性能瓶颈。
第二种方案:OMS 将数据变更下发到 Kafka,通过这种方案,数仓能够以较低的延迟快速抽取数据,从而满足实时报表及其他高时效性业务需求,解决了方案一的性能问题。同时由于数据仓库和部分数据同步到 Oracle 需求,对实时性要求极高,也必须采用 OMS 到 Kafka 的链路实现。为此,需要开发数据同步工具,完成下游从 Kafka 到 Oracle 的数据流转需求。
图 6 MyCat 替换为 OceanBase 同步数据至下游的两种方式
关于 OMS 的使用经验,我们总结了几点实践中遇到的问题与注意事项。
其一,OMS 插入存在冲突会在日志打印,不影响复制。OMS 在插入数据时,若检测到数据冲突,会在日志中记录相关信息,不会中断复制流程。这意味着,例如在分库场景下,即使存在组件冲突,OceanBase 通过 OMS 的链路仍将持续运行,不会因此中断。对此,我们需在后续工作中加强数据校验机制,及时发现并处理潜在的数据一致性问题。
其二,OMS V4.2.5.2 之前的版本需要关注字段超过 4K 的复制情况。在 OMS 4.2.5.2 之前的版本中,对于超过 4K 的 LOB 字段行外存储的话,执行 DML 时 OBCDC 可能不吐出 LOB 列的前镜像,导致下游数据不一致。具体表现为:若某行数据未对该大字段进行修改,OMS 在将变更消息下发至 Kafka 时,会将该字段内容置为空。这一行为对一般依赖全镜像复制的数据同步工具而言并不友好。例如,如果仅修改更新时间,也可能导致大于 4K 的字段被置空,从而影响下游数据的完整性,建议使用 4.2.5.2 以后的版本(OMS 4.2.5.2 版本已解决该问题)。
其三,OMS 下发数据变化到 Kafka,从消费角度 Hash 性能最优,但是要考虑是否存在唯一键的问题。OMS 支持两种数据变更下发方式:一种是以表维度,另一种是以主键 Hash 分区维度。从消费者角度考虑,主键 Hash 分区的性能最好。但需要考虑某些场景目标端存在的唯一键问题,可能会导致数据丢失。
以我们遇到的场景为例:假设有一张表(tab1),有一个主键(id)和一个唯一键(uniq_col),我们对该表依次执行以下三步操作:
1. 插入一行数据:insert into tab1 values(1,'a');
2. 按照唯一键删除数据:delete tab1 where unique_col = 'a';
3. 插入一行 ID 为 2 的数据:insert into tab1 values(2,'a');
如图 7 所示,当上述变更通过 OMS 下发至 Kafka 时,若采用 ID 作为哈希值,(1,'a') 和 (2,'a') 很可能不被分发到同一个 Partition 中。在 Partition1 中,同时存在 insert 和 delete,而在 Partition2 中,只有一条 insert 记录。
图 7 OMS 下发数据变化到 Kafka 时可能存在的结果
由于下游消费者在消费消息时存在各种情况,可能不按照语句执行顺序进行,无论下游的数据同步采取 insert into 模式还是 insert into ... on duplicate update... 模式,都有可能遇到 (2,'a') 数据丢失的情况。
如果下游的数据同步采用 insert into 模式,在按照图 8 的顺序消费时,先插入(1,'a'),再继续消费 msg3 插入 (2,'a') ,此时由于 a 列冲突不再执行,最后消费 msg2,导致 (2,'a') 数据丢失。
图 8 下游的数据同步采用 insert into 模式
如果下游的数据同步采用 insert into ... on duplicate update... 模式(见图 9),先插入 msg3 即 (2,'a') ,后续基于 insert into ... on duplicate update 模式,在消费 msg1 时,一旦 a 列出现冲突,会将 a 列的值更新为 1,最后消费 msg2,导致 (2,'a') 数据丢失。
图 9 下游的数据同步采用 insert into ... on duplicate update...模式
上述 OMS 以主键 Hash 分区模式下发 Kafka 在消费时可能存在的问题,本质是因为在主键 Hash 分区模式下,不同 Partition 存在并发修改同一行时同时叠加了唯一键导致的。因此在上述 OceanBase 架构下 OMS 将数据变更下发到 Kafka 的第二个方案中,消息按表还是主键 hash 分区取决于两点:一是对高性能有无需求,二是如果下游的表没有唯一键,也可以按照主键 Hash 分区方式进行。
反向同步
图 10 是业务切换前后的数据链路,不同颜色的链路代表不同的数据传输工具:红色链路代表 Otter、蓝色链路代表 OMS、绿色链路代表百丽自研的数据同步工具 SQLapplier、黑色链路代表其他工具。
图 10 业务切换前后的数据链路
切换前,业务数据通过 OMS 同步到 OceanBase,OceanBase 通过 OMS 下发到 Kafka。同时在上线前需要做数据同步测试,通过 Kafka 将数据同步到测试 Oracle 和测试 MyCat,持续验证同步工具的性能和功能适配。
数仓可以提前验证和切换。
业务切换时,需要暂停应用和上游业务的同步,此时 MyCat 和 OceanBase 处于相对静止的状态。然后需要停止 OMS,将 Kafka 反向同步到 MyCat 和 Oracle,再将上游业务指向 OceanBase 即完成了切换过程。反向同步的意义在于,如果在切换初期出现任何问题可以及时回切,提高系统容灾能力。
第二步:数据校验
数据流转完成后一般需要进行数据校验,对于单库迁移,可以直接使用 OMS 完成数据校验,在重复多次校验时,可根据数据不一致情况生成订正数据。如果源端是 MyCat 的情况,可以搭建源端为 MyCat,目标端是 OceanBase 的校验,但由于百丽使用了很多 Otter 工具,同时有一些 MySQL、Oracle 的异构数据库校验需求,因此使用了内部自研的工具(见图 11)。
图 11 使用自研工具进行数据校验
数据校验基本原理
以图 12 为例,如何校验对应行数据在目标端是一致的,即把各个字段拼成一个字符串,然后做 crc32 校验。如果两端的 crc32 匹配,则源端和目标端的数据一致。如果对某一端的数据做简单修改(如加一个空格),那么数据将会有很大的变化。对于整表来说,将按照一定的行数拆成多个 chunk,以 chunk 的维度进行目标端和源端的 crc32 比对。如果出现数据不一致的情况,将进行重试,经过多次重试后数据还是不一致时,会进行分裂;如果多次分裂数据还是不一致,将最终转换为上文行数据的暗行(字符串)来进行校验。
图 12 例证校验对应行数据在目标端是一致的方法
数据校验问题汇总
图 13 是将平台中 OceanBase 作为源端,Oracle 作为目标端的数据校验过程,在我们测试过程中一共发现了 4 个问题。
1. 业务数据异常。由于 MyCat 约束较小,随着长时间使用,以及有变更迁移数据等操作,可能会遗留一些历史问题,例如 ID 重复。
2. 唯一键约束范围差异导致数据丢数。MyCat 的唯一约束只能约束到 DB 分区维度中的约束,但在 OceanBase 中是全局约束,这种差异也会导致数据丢失。
3. Kafka 消费 Hash 分区、下游唯一键约束丢数。
4. OBServer V4.2.5.2 之前 4K 大字段丢数。
图 13 将平台中 OceanBase 作为源端,Oracle 作为目标端的数据校验过程,数据校验覆盖了数据治理和数据正确性、数据一致性校验,在上线前解决存在的数据异常问题,是一项非常重要的工作。
第三步:SQL 兼容及性能测试
在打通数据链路、完成数据校验后,需要解决的就是 SQL 兼容性和性能问题,例如如何对比 MyCat 和 OceanBase 的数据库性能差异,OceanBase 性能是否能满足我们的业务需求等。针对上述需求,一个朴素的方法是:可以将 MyCat 中所有 SQL 在 OceanBase 中实现,即可完整地测试兼容性问题以及性能表现。
为此我们开发了流量回放功能,如图 14 所示,通过数据库管理平台在各个 DB 中采集全量日志,然后解析为 CSV 格式,最终将所有 CSV 文件整合即可形成解析报告,用于分析集群层面的整体 SQL 分布、DDL、DML 等情况。将 CSV 回放到 MyCat、OceanBase 后,形成回放对比报告。
图 14 流量回放的执行过程
看到该过程的你可能会有两个疑问:
1. 为什么用全量日志?全量日志的好处在于全局变量便于开关,如果发现性能有压力,可以选择关掉。
2. 为什么用 CSV 格式?这是因为考虑到兼容性问题。例如目前 OceanBase 能够将 SQL 转成 CSV 格式,后续可以直接从 OceanBase 的 SQL Audit 中捞取 SQL,并以 CSV 的格式保存,同样可以跑通回放流程。
回放报告
回放报告中的统计信息(见图 15)包括:将所有回放 SQL 进行参数化形成模板生成对应的 SQL ID;该 SQL 使用到的表;每个 SQL ID 的最小响应时间、最大响应时间、平均响应时间、执行次数、错误次数、对应 SQL 等。
图 15 回放报告中的统计信息
通过回放报告,我们可以进行兼容性分析,确定优化范围和任务分配,并持续进行回放,从而提升工作效率。
兼容性分析。通过比较源端和目标端的执行结果,检查是否存在兼容性错误。比如报告中显示存在错误,需要进一步核实错误原因是超时还是 SQL 语句本身不兼容,从而准确定位 SQL 语句的兼容性问题。
确定优化范围。回放报告可以帮助我们确定需要优化的 SQL 语句范围。由于报告生成了大量 SQL 语句,并非所有 SQL 语句都需要优化。报告中提供了每个 SQL 语句的平均响应时间、执行次数等数据,通过这些数据可以评估 SQL 语句性能,从而明确优化范围。
任务分配。在确定了优化范围后,如何合理分配任务成为一个关键问题。最初,任务分配可以比较随意,直接根据 SQL ID 进行分配,但在每周的慢查询研讨会中,我们逐渐发现这种分配方式可能导致工作效率低下。为了改善这种情况,我们利用之前收集的表组信息 tablelist ,以表组为维度进行任务分配,这不仅提高了慢查询治理的效率,也避免了重复工作。
持续进行的回放。由于回放报告会多次回放,尤其是在流量变化较大的系统中,如财务系统在月初和月末的流量可能差异很大。因此,我们会从月初到月末持续抓取流量,并进行多次回放。然而随着报告数量的增加,横向比较越来越不方便。为了解决这个问题,我们将报告整合到平台中,并以 SQL ID 作为关键要素,将每次回放的报告串联起来,以便于分析和比较。
SQL 持续治理及跟进
图 16 是我们平台的 SQL 持续治理及跟进面板的截图,可以展示每条 SQL 在每一轮回放中的变化,每个 DBA 只需要关注自己负责的 SQL 即可。例如图中所示的 SQL,我们在根据表组进行调优后,可以看到它的最大响应时间等数据明显下降,证明回放报告对于 SQL 诊断和治理带来的效率提升是非常直观的。
图 16 平台的 SQL 持续治理及跟进面板
此外,值得一提的是 OCP 有一个非常实用的功能,可以根据特定时间点恢复数据。在进行压力测试及流量回放过程中,可能会涉及对数据执行 DML 操作,从而对数据造成修改。面对这种情况,OCP 能够迅速将数据恢复至某一时间点的数据副本,便于我们立即将数据投入使用。使用完毕后,可以将其删除。对此,我们认为这一功能极具价值。
SQL 问题分类
在进行 SQL 治理和调优过程中,我们共发现了四个问题。
问题 1:部分 SQL 不兼容。
在 SQL 使用过程中,我们通常用“--”进行注释,放在 SQL 语句最后。在 MySQL 中一般不会发生报错,但在 OceanBase 中报错了,研发团队直接进行了修改。值得肯定的是,在回放了大约 4.5 万个 SQL ID 后,发现的不兼容问题仅有这一个,由此看出 OceanBase 对 MySQL 5.7 版本的语法兼容度是非常高的,基本无需在兼容性方面投入过多的工作量。
图 17 不兼容的 SQL
问题 2:RPC 代价高。
当使用多组模式进行查询时,如果 SQL 涉及多个 OBServer,可能会导致网络开销增大,特别是在处理大量数据的情况下,可能会显著降低查询效率。解决该问题需要进行分片表表组设计或者对于相对稳定的主数据表,设计复制表。此外,为了快速判断是否为 RPC 问题,可以通过恢复一个单主环境,并在该环境中执行 SQL,然后与多主环境进行性能对比,从而有效判断问题是否由 RPC 代价引起。
问题 3:分区裁剪。
分区裁剪是另一类需要花费大量时间进行调优的问题。例如,在涉及 DTL 订单明细表的 order by 关联查询中,指定某个大区条件,在 MyCat 中没有图 18 所示红框中的条件,这是因为 MyCat 的分区规则相同,即在物理层面进行了隔绝,本来就在一个大区内,所以不需要对大区进行指定。而在 OceanBase 中,如果将这个条件去掉,会引发 om 表正常进行分区裁剪,但 od 表不知道需要在这个大区内进行,因此 OceanBase 需要指定这个条件以确保分区裁剪的正确性。这是一个非常典型的分区裁剪问题,其根本原因在于 MySQL 的机制在某些方面并不完善,原本物理隔绝的 SQL 在 OceanBase 是一个完整的库,这就需要我们在 OceanBase 中进行相应的调整和优化。
图 18 补充分区条件
问题 4:执行计划问题。
执行计划问题涉及几个关键参数。
partition_index_dive_limit 参数是 SQL 采样分区参数,可能会影响执行计划的评估,如果采样分区较小且数据为空,可能会导致采样误判,影响代价评估,建议根据实际需求将参数调大。
大小参数的问题,指同一 SQL 在不同变量下读取的数据差异较大,但使用了相同的执行计划,可能会导致性能问题,此时可以使用 /*+USE_PLAN_CACHE(NONE)*/ 进行规避,但这会使得每次执行该 SQL 都硬解析,有额外的 CPU 开销,需要综合评估使用。
如果 in 参数过多,可能会导致硬解析时间过长,此时可以适当调整参数_inlist_rewrite_threshold,使 in 参数到达一定阈值后可以进行改写以避免硬解析的代价。
问题汇总
在实际应用中,我们还遇到了一些其他问题:
local rescan 计划不优,低代价的 nlj 计划由于 local rescan 的规则被错误裁剪,导致 SQL 最后走了高代价执行慢的 hash join,该问题出现在 OceanBase V4.2.5.3 之前的版本,已经在 OceanBase V4.2.5.3 版本修复。
调整 tablegroup,手动发起均衡,若存在空分区,均衡计算可能会导致任务卡住,该问题出现在 OceanBase V4.2.5.3 版本,已经在 OceanBase V4.2.5.4 版本修复。
包含复制表的 SQL,一定情况下会存在无法复用执行计划的情况,该问题出现在 OceanBase V4.2.5.4 版本,已经在 OceanBase V4.2.5.5 版本修复。
切换收尾:平台适配
我们内部使用 Archery 工单平台完成 SQL 的管理和发布,并且现有的 MySQL 等数据库也都在使用 Archery 工单平台,因此我们计划使用该平台接入 OceanBase。
目前,OceanBase 已经对接了 goInception 项目(https://github.com/whhe/goInception),可以实现 OceanBase 资源类型的工单回滚,即结合 OBServer 完成 SQL 的回滚操作。
在使用 Archery 平台管理 MySQL 时,我们通常通过 ptosc 或 gos 等方式实现 Online DDL 操作。然而,这种方式对于 OceanBase 的离线操作,可能会直接锁表。
针对这种情况,我们期望达到的效果是:提交工单时,无论是 DBA 还是研发人员都能够识别出操作是 Online 还是 Offline。过去我们依赖于肉眼判断,为了改进这一流程,我们增加了一项小功能:在提交工单时,我们会在测试环境中的 OceanBase 中运行一遍,检查 Table ID 是否发生变化。如果 Table ID 发生变化,则表明操作是 Offline 的;如果没有变化,则表明操作是 Online 的,告警信息如图 19 所示。
图 19 告警信息
这一设计虽然简单,但效果显著,研发人员在提交工单时可以一目了然地知道操作是在线还是离线,大大提高了工作效率。
百丽核心系统为什么选择 OceanBase?
以上就是百丽财务系统从 MyCat 迁移至 OceanBase 的技术经验总结,在此过程中,非常感谢 OceanBase 社区团队在我们项目测试及切换过程中的密切关注与大力支持。
那么,为什么我们会选择 OceanBase,而不是同样作为开源分布式数据库的 TiDB、PolarDB……呢?
理由可以归纳为三个方面。
第一方面是 OceanBase 的技术优势:
可靠。Paxos 多副本机制,RPO=0,故障自动切换,数据零丢失。
弹性。单机型与分布式模式可在线互转;多租户隔离;高压缩比降低存储成本;容量可按需横向扩展,无需提前重度预估。
统一。原生 HTAP,同一套引擎同时支撑 TP、AP、KV 及向量检索,后续引入新负载无需新增技术栈。
易用。提供 OCP、OMS、ODC、OBAgent 等完整工具链,显著降低部署、迁移、监控、运维门槛。
第二方面是社区活跃,OceanBase 保持完全开源与快速迭代的风格,对于用户的问题及时响应,确保了用户的技术交流渠道畅通。同时,社区经常开展技术交流活动与培训课程,不断加强用户对于问题的解决能力。此外,用户对于其版本发布节奏也是可预期的。
第三方面是行业验证,OceanBase 在金融、运营商、零售等高要求行业规模化上线,历经核心系统长时间运行考验,稳定性已经得到大量企业的充分证明。








评论