数据库迁云是一个复杂工程,对于传统企业来说,数据库不仅沉淀业务数据,还沉淀了大量业务逻辑,数据迁移过程复杂,风险高。本文借用客户核心系统数据库迁移到PolarDB为例,介绍数据库迁移过程中遇到的挑战、对应的解决方案,供大家参考。
1. 前言
数据库迁云是一个复杂工程,对于传统企业来说,数据库不仅沉淀业务数据,还沉淀了大量业务逻辑,数据迁移过程复杂,风险高。本文借用客户核心系统数据库迁移到PolarDB为例,介绍数据库迁移过程中遇到的挑战、对应的解决方案,供大家参考。
2. 需求和挑战
某运营商客户核心系统是一个相对老旧的系统,基于Oracle开发,历经数年研发迭代,历史包袱沉重,ISV大量使用Oracle的特性,应用和数据库耦合紧密。在前期的数据库迁移评估与调研过程中,我们详细评估和分析了客户的数据库画像,总结了我们面对的主要风险和挑战
●【兼容性】应用和Oracle数据库特性耦合紧密,客户侧要求尽量少的改动应用,对polardb的兼容性提出了很高的要求
●【数据一致性】客户侧数据库有28000张表,其中大部分是无主键表,有主键表只占12%,dts无法保障无主键表的数据一致性,大量无主键表对数据一致性的保障带来很大挑战
●【数据一致性】客户侧没办法禁止DDL,应用系统会有自动的DDL,以及频繁的应用发布,DDL支持对数据同步和数据一致性提出了更高的要求
●【数据一致性】有大量ROWID类型的字段,用于表和表之间的关联,polardb rowid实现和Oracle有差异,直接迁移过来会破坏对应关系
●【性能】Oracle有非常强大的优化器,很多sql迁移到polardb后有可能会变成慢sql,性能问题较多
整个项目涉及多方角色,多家ISV、客户、阿里,如何高效和各方沟通协调,对整个项目组也是个挑战。
3. 方案选型
经过分析和调研,客户侧数据库系统呈现如下特点:
数据量大,数据库对象多,并发请求多。单库数据量数TB以上,表数量数万张,日请求量数十亿以上。
业务复杂,核心业务库承载了最核心的业务,上游业务依赖链路长,牵一发而动全身。
应用场景多,因历史原因,除了大量Java编写的应用代码,还存在C语言开发的代码。
数据链路长,有大量和离线数仓交互的场景,不仅仅要关注联机事务交易场景,还需要兼容ETL抽数和离线计算回流场景。
同时,客户要求尽可能减少业务侧的改造,结合业务特点以及客户的要求,我们给客户推荐PolarDB Oracle高兼容版数据库(以下简称“PolarDB O引擎”)来支撑客户的业务。PolarDB O引擎采用存储和计算分离的架构,所有计算节点共享一份数据,提供秒级的故障恢复、全局数据一致性、一写多读和读写分离服务,高度兼容ORACLE语法,非常契合客户的场景。PolarDB O引擎既融合了商业数据库稳定可靠、高性能、可扩展的特征,又具有开源云数据库简单开放、自我迭代的优势。详细架构图如下:
4. 兼容性保障
该项目中,业务侧大量使用Oracle独有的特性,应用和数据库耦合紧密,例如:
1.rowid当做业务主键,业务大量使用rowid进行dml
2.业务SQL中会查询数据字典,例如all_objects、all_tab_columns等
3.polardb事务特性和Oracle事务特性不一致,导致业务异常
4.部分数据库函数不存在,或函数表现和Oracle有差异
rowid特性支持
polardb 20210731 之前的版本是不支持rowid特性的,在该项目中,应用大量依赖rowid进行DML,且业务不愿意进行改造,polardb内核实现了rowid特性,用于支持该场景。polardb rowid主要通过自增序列实现,针对每一张表添加bigint类型的隐藏列rowid,并对rowid隐藏列创建单独sequence,rowid特性通过polar_rowid_type=oid/sequence参数来控制开启或者关闭。
oracle数据字典
业务应用和Oracle特性耦合紧密,存在大量查询数据字典的场景,且业务不愿意改造。研发团队提供了模拟Oracle 数据字典的视图,解决了该问题,后续在其他项目上也能实现对Oracle数据字典查询场景的兼容,应用可以像使用oracle一样的方式来查询数据字典。
polardb事务特性和Oracle事务特性不一致
Oracle的commit和polardb存在差异,polardb的commit默认会释放相关资源。当在同一个session读取了resultset,在当前session 循环fetch并操作DML + commit的时候,Oracle能正常运行,polardb会因为resultset的相关资源被释放而报错:
portal 'C_1' does not exists
此场景可通过添加holdable portal hint解决,
SELECT /*+ polar_holdable_hint */
该方式的缺点是需要客户侧进行代码修改,后续内核层面也会兼容此场景。
函数兼容性问题
业务大量使用了to_char to_date chr等函数,polardb对Oracle风格的函数已经有了很友好的支持,但是在一些细节上还是有所不同,例如Oracle支持select to_char('2021-10-21','yyyy-mm-dd')、to_date(20210101010101,'yyyymmddhh24miss') 等,polardb就不支持上述写法,为解决此问题,在客户现场手动创建了大量自定义函数,用于兼容Oracle特性。
#兼容to_date(sysdate)
create or replace function
to_date(timestamp without time zone)
returns timestamp without time zone
language sql
IMMUTABLE
as
$function$ select $1
$function$;
#兼容rowidtochar函数,polardb rowid类型是bigint
CREATE OR REPLACE FUNCTION ROWIDTOCHAR(bigint)
RETURNS text
LANGUAGE sql
IMMUTABLE
AS $function$ SELECT $1::text $function$;
#兼容to_date(20210101010101,'yyyymmddhh24miss')
CREATE CAST (bigint as varchar)WITH INOUT AS IMPLICIT;
因篇幅有限,以上只是介绍了项目中兼容性问题中的一部分,大量兼容性问题的解决,得益于和产研团队的背靠背合作。
5. 性能保障
压力测试也是非常重要的步骤,没有经过压力测试的数据库迁云操作失败概率是非常高的,不同数据库的性能表现是有差异的,在高并发场景下,性能差异对应用的影响非常敏感。我们采集了Oracle的全量业务查询,通过流量回放到PolarDB的形式完成了多轮压测。通过压测我们发现了一些有性能差异的sql,通过优化和调整,尽量做到两端性能表现一致。
起初项目组所有人对性能问题并不太重视,预估性能压力不会很大。但是在实际压测过程中性能问题暴露出来,出现大量的慢sql,polardb的平均执行时间远远大于Oracle,上线风险很高,客户侧开始质疑polardb的产品力。
临近割接,时间紧迫,项目组加班加点分析sql,发现有大量的sql没有走到索引,导致运行效率很差,得益于Oracle强大的优化器,这些sql在Oracle运行效率并不差,但是在polardb,性能问题凸显出来。汇总了所有的sql,有上万条sql需要优化,任务重,时间紧,全部优化一遍几乎不可能,所以只能把有限的力量投入到最重要的事项上。为了区分哪些sql重要,抓取了生产所有的sql,根据执行频率进行倒排,优先关注TOP100内的慢sql,优化完毕后,继续优化TOP200内的慢sql,以此类推,优化手段主要是加索引,少量场景需要改写sql。
有些场景下仅仅使用加索引、改sql的方式并不能解决问题,例如分区表。现有版本的polardb分区表性能不佳,所以针对分区表性能差的问题可以考虑转换成普通表。
6. 数据一致性保障
在以往的项目割接中,为保障割接成功率,一般会要求禁止DDL,所有表加主键。但在该项目中,大部分的表都是无主键表,且每天都有大量DDL,理想化的割接条件均不存在,数据一致性保障挑战极大。
如何保障正向同步数据一致性
为保障Oracle到polardb同步的数据一致性,首先需要解决无主键表问题,DTS无法保证无唯一键、无主键表的数据一致性,这是第一个需要被攻克的难题。虽然这些表没有主键和唯一建,但是Oracle有没有什么字段或者特性是具有唯一属性的?答案是有,Oracle ROWID具有唯一性,并且客户在业务逻辑中也把ROWID当做主键来用。找到了唯一键后,后面要做的事情是把ROWID同步到polardb,也就是DTS需要支持对ROWID的迁移,事情似乎变得容易起来。但是熟悉Oracle的人都了解ROWID,ROWID是对一行记录的物理位置的描述,具有唯一性,但是行的物理位置是会变动的,如果分区表修改了分区键、或者做了表空间收缩动作,会导致行迁移,ROWID也随之变化。如果在迁移过程中Oracle发生了行迁移,就会导致数据不一致。虽然存在数据不一致的风险,但是这是目前最有可能迁移成功的方案了,方案示例:
其次还要解决DDL造成的数据不一致问题,为解决无主键表一致性问题,对polardb 所有表添加ROWID列和ROWID列唯一索引,DTS把Oracle rowid数据迁移到polardb ROWID列,确保一致性。但是客户侧存在drop+create的DDL,DTS正向同步支持DDL,所以会造成一些表丢失ROWID列,不能保证一致性。不仅如此,日常发布产生的DDL、每天新建表的操作,都会影响数据一致性。
针对以上方案中的问题,设计了三次数据同步,用于解决正向数据同步一致性问题,所有正向同步链路严格按照一下步骤实施(供参考):
1-1 |
全量表结构同步 |
生产环境数据库对象进行全量同步 |
|
1-2 |
第一批数据同步 |
全量+增量数据迁移 |
|
1-3 |
收集统计信息 |
全量完成之后收集一次统计信息 |
|
1-4 |
核心表数据校验 |
对数据库表进行分层,分为核心表和非核心表,因为全量数据稽核耗时长,优先对核心表进行稽核 |
|
1-5 |
Oracle库给eoa_user添加dba权限 |
Oracle库给eoa_user添加dba权限,用于回流链路 |
|
1-6 |
count校验 |
反复运行count校验,找出过程中不一致的表 |
|
1-7 |
表结构对比 |
反复运行表结构对比脚本,找出表结构不一致的表 |
|
1-8 |
第二批数据同步 |
根据校验结果,找出不一致的表,如果存在大表不一致,那么需要提前同步,用于缩减停应用后的第三批数据同步的时间。同步方式:全量+增量 |
|
2-迁移阶段 |
2-1 |
差异表表结构同步 |
检查表结构是否一致,检查是否有新增object,检查是否有删除的表结构,确保两边表结构一致 |
2-2 |
创建反向链路 |
提前创建好反向回流链路,保存不启动 |
|
2-3 |
停应用 |
应用停机 |
|
2-4 |
源端Oracle库杀会话,锁用户 |
||
2-5 |
停止正向同步链路 |
DTS 停止正向链路同步 |
|
2-6 |
第三批数据迁移 |
停机之后需要全量迁移的表: 1、新建的表 2、由于 DDL 导致无 ROWID 的表 3、数据不一致的表 4、表结构不一致的表 |
|
2-7 |
核心表数据校验 |
运行脚本执行Count数据核对,确保所有表数据一致 |
|
2-8 |
抬高sequence |
select 'alter sequence '||SEQUENCE_OWNER||'.'||SEQUENCE_NAME ||' restart with '|| (last_number+1000) ||';' from dba_sequences where SEQUENCE_OWNER in ('xxx'); |
|
2-9 |
删除指定表的ROWID列 |
ROWID列会影响部分业务,需要提前删除。 |
|
割接阶段 |
3-1 |
业务读流量验证 |
业务只读流量切换到 PolarDB O 进行验证 |
3-2 |
启动备份 |
启动目的端PolarDB O库增量备份 |
|
3-3 |
启动回流任务 |
启动 PolarDB O 到 Oracle 的数据回流任务 |
|
3-4 |
回流验证 |
找一张表,插入一条测试数据验证回流 |
|
3-5 |
业务写流量验证 |
业务验证测试 |
反向链路数据一致性,从polardb回流到Oracle
解决完正向链路的数据一致性问题,接下来更大的挑战是反向链路的数据一致性保障。所有正向链路遇到的问题,反向链路都会遇到,核心需要解决下面两个问题:
1.dts不支持polardb->Oracle的DDL同步,客户侧大量的DDL无法同步,包括结构同步和数据同步
2.大量无主键表,无法保证数据一致性,如果DTS链路重启可能造成数据重复
经过反复的分析、讨论和测试验证,完全依赖DTS增量同步无法保证数据一致性。polardb varchar比Oracle varchar2能存放更长的字符串,回流同步任务可能会因为Oracle 表字段长度不够导致同步失败,所以可以预见DTS一定会发生重启,一定会出现数据不一致。
DDL同步+数据修复
首先需要解决DDL数据同步的问题,通过结构对比工具检查表结构的变更,差异的部分手动同步过去。对于新创建的表先通过copy导出CSV文本,在通过sqlloader导入Oracle的方式进行数据修复,该方案适合同步大表和DDL的表。如果发生回切,该步骤的耗时是最长的,所以不能等到要回切了才进行修复,必须每天把日表进行修复,减少后面回切的耗时。
无主键表问题
我们梳理了所有的业务表,区分哪些是热表、冷表,热表中进一步区分哪些是核心表,哪些是非核心表。针对核心热表增加主键,确保核心表数据一致性。非核心热表尽可能增加主键,不能增加主键的表会通过常态化的数据校验来检查是否一致,如果不一致会对数据进行修复。
7. 总结
该项目是一次完整的核心业务从Oracle迁移到PolarDB的实践,该项目中我们遇到了数据一致性、兼容性、性能等各种问题,最后一一解决。在沉淀经验的同时,我们也意识到工具在数据库交付中的重要性,后续我们开发了frodo流量回放工具,用于解决Oracle、db2、mysql迁移和升级过程中的sql兼容性评估、压力测试需求,进一步降低数据库交付的难度。不仅于此,阿里云数据库交付团队大量使用数据迁移工具DTS、sql智能优化工具SQLA、数据库一致性校验工具青天鉴、数据库兼容性评估工具ADAM等,覆盖了数据库交付的各个主要环节,有效提升数据库交付的标准化率。