
在去O上云项目过程中,阿里云项目组与我司密切合作,帮助我们理清技术架构并定制了一套完整的去O迁移方案,在双方近半年的不懈努力下,我们共同解决了迁移评估、驱动适配、业务改造等众多复杂问题,于2024年4月5日和5月25日圆满完成了两次关键的数据库迁移割接任务,实现了从线下IDC自建Oracle成功迁移至阿里云PolarDB PostgreSQL版 (兼容Oracle)。
这种团队紧密协作的方式对于此次迁移割接任务起到了至关重要的作用。目前PolarDB 作为核心数据库支撑了我司C端前程无忧、B端网才等核心业务。我们真诚地感谢阿里云团队在此次项目中所作的巨大贡献,并期待在未来的工作中继续保持这种密切的合作伙伴关系,共同推进我们业务的持续发展。
前程无忧-技术研发中心-业务研发部 - 许益平
客户背景
综上所述,由于历史原因客户的技术架构极具多样性,几乎兼容了大多数主流开发语言。这种多技术栈的混合性,对于任何试图替换 Oracle 的行动构成了一项巨大的挑战。而前程无忧研发团队为了更好的支撑业务,降本增效,对核心Oracle数据库的替换决定迎难而上,和阿里云通力合作,共同推进。因此从技术层面双方需要面对的就是:适配新的数据库架构不仅需要解决语言和框架层面的兼容问题,还必须确保数据库层面所有操作的平滑过渡,以保持业务连续性和系统的稳定性。
PolarDB解决方案
端到端产品化、规模化的去O解决方案
基于阿里巴巴集团去IOE的实践经验以及阿里云服务万千企业客户的技术沉淀,阿里云传承并发展了去O能力,积累了大量去O方法论和配套产品,如ADAM、DTS、PolarDB PostgreSQL版(兼容Oracle),形成了一套端到端的产品化、标准化、规模化的去O解决方案,从而帮助企业更加平滑迁移改造,降低客户“去IOE”风险。

多模态驱动适配复杂业务
驱动概述

OCI 驱动的适配

初始化阶段
代码适配与驱动整合:首先,我们深度参与客户的代码调整工作,确保其能够顺利集成Polar OCI驱动。这一过程涉及将原有业务逻辑与数据库交互代码(包括连接管理、CRUD操作)与Polar OCI库的接口(如OCIInitialize, OCIEnvInit, OCIHandleAlloc等)紧密对接,为后续的无缝迁移奠定基础。 库替换与连接重构:紧接着,协助客户逐步将Oracle OCI库替换成Polar OCI库,通过一系列步骤,如设定服务器连接(OCIServerAttach)、会话初始化(OCISessionBegin)等,顺利完成数据库目标从Oracle到PolarDB的转变,确保底层通信协议的兼容与高效。 编译与服务启动:利用Tuxedo的编译工具链,我们对已完成适配的C代码实施编译与链接,生成服务端程序。此外,我们还优化了Tuxedo的标准初始化接口tpsvrinit,通过执行tmboot命令顺利部署服务,实现了与PolarDB的稳定连接。 环境验证与启动:最后,在此阶段末尾,我们确保所有初始化步骤正确执行,通过Tuxedo环境成功启动服务,标志着数据库连接与基础功能验证均达到预期,为应用层的深入适配铺平道路。
应用阶段
模块级功能适配:深入到应用层面,我们逐一配合客户完成数据查询、更新模块以及特定业务逻辑函数的适配工作。通过精确调用Tuxedo服务,确保客户端能够无缝执行数据库操作,这一过程中,C代码逻辑与Polar OCI接口的融合是关键,确保了业务连续性和性能稳定性。 深度集成Libpq驱动:Polar OCI驱动内置了对Libpq驱动库的高级封装,为客户端提供了直接通过Libpq接口与PolarDB交互的能力,这一设计进一步简化了开发者的接入难度,提升了整体系统的兼容性和灵活性。
总结
通过上述两阶段的适配操作,我们在代码级别上完成了从连接到业务逻辑的全面适配,特别是在面对Tuxedo环境下OCI业务模块的复杂迁移挑战时,我们通过Polar OCI的深度整合与优化,有效解决了连接性、操作性及语法兼容性等问题,保障了业务在迁移过程中的不间断运行。这一迁移策略不仅满足了客户ToB与ToC业务的多元化需求,还为未来云原生架构的扩展奠定了坚实基础。
Pro*C 驱动的适配

初始化阶段
代码适配与ECPG集成:首先,我们的专家团队深入客户的代码基础,着手将原有业务逻辑与数据库操作代码(即含嵌入式SQL的PC代码)适配至ECPG驱动。这一阶段聚焦于保持业务逻辑不变的同时,确保ECPG的有效集成。 编译工具链升级:接着,我们将客户的编译环境从Oracle Pro*C转向ECPG编译器,这一转换要求对Makefile和依赖文件进行相应调整,以确保ECPG能够准确识别并处理嵌入式SQL代码,将其转化为调用ECPG接口的纯C代码。 编译与服务配置:通过修改后的Makefile,我们指导编译过程,将ECPG处理后的C代码与Tuxedo的编译模块相结合,编译链接成server程序。随后,通过执行tmboot命令,借助Tuxedo的标准化接口tpsvrinit成功启动服务,实现与PolarDB的初次握手。
应用阶段
模块全面适配:进入应用层面,我们携手客户逐一完成数据操作关键模块(如查询、更新、校验、会员管理、任务调度及网页生成)的ECPG适配。确保各模块接口函数无缝对接ECPG库,保障业务逻辑的执行与数据库操作通过ECPG接口紧密相连,维持业务流程的连续性和稳定性。 深化Libpq集成:ECPG驱动之下,我们充分利用其对Libpq驱动库的高级封装,为客户端与PolarDB之间搭建起高效、可靠的通信桥梁。这一策略确保了客户端能够通过Libpq接口函数,实现对数据库的流畅交互。
总结
通过以上策略,我们不仅在代码与逻辑层面成功适配了Polar ECPG驱动,还在技术栈转型上取得了实质进展,有效帮助客户将数十项服务从Oracle Pro*C平稳迁移到Polar ECPG。这一过程不仅解决了数据库目标变更带来的连接、操作及语法兼容性等系列挑战,还保障了业务在从Oracle到PolarDB转换期间的正常运行。
MyBatis框架的适配(JDBC)
MyBatis 在处理时间类型数据时遇到了与 JDBC 驱动的适配问题。这里我们将介绍 JDBC 处理数据类型的过程和问题解决方案:(参考文档https://help.aliyun.com/zh/polardb/polardb-for-oracle/jdbc-o)

JDBC 处理数据类型流程
预处理语句(Prepared Statement) 参数绑定涉及将 Java 中的值映射到 PostgreSQL 的数据类型。 设置参数 & 绑定处理(Parameter Setting & Binding) 使用 setXXX() 方法,驱动记录在对应参数索引位置绑定的 Java 类型及值。 针对每个参数,生成对应的格式化值,比如将其转换为字符串或二进制表达。JDBC 驱动会根据之前调用的 setXXX() 方法来确定参数的 PostgreSQL 数据类型,并将这些信息以及参数的实际值发送到服务器。 类型推断(Type Inference) 服务器接收到参数和类型信息后,将其与预先创建的查询计划结合,进行类型匹配和推断。 结果返回(Result Return) 数据库处理结果后,通过结果集返回给 MyBatis 框架的ResultSetHandler,从而上传处理结果。
存在问题:在处理 setXXX() 方法时,JDBC 驱动丢失了TIMESTAMPOID 。这个问题是由于社区版本 PostgreSQL 的 JDBC 在处理 TIMESTAMP 类型时的保守策略引起的,从而导致了数据库无法正确接收 TIMESTAMP 类型的时间数据。
解决方案
ODBC 驱动的适配
参考文档:https://help.aliyun.com/zh/polardb/polardb-for-oracle/odbc2-0
关于ODBC 问题的阐述
关于ODBC 解决方案

从数据库中提取了64位的 SYS.DATE 数据类型。 通过ODBC驱动,我们成功识别了这种独特的64位日期类型,并在 copy_and_convert_field 函数中进行了单独处理。此过程包括将其格式化为类似于时间戳的格式进行解析。 结果是,返回至应用层的日期类型数据现在包含完整的年、月、日以及时、分、秒信息。
通过这套方案,我们有效地解决了PostgreSQL协议在 DATE 类型支持方面存在的局限性。此项创新确保了数据类型的完整兼容,从而实现了在客户数据库中无损的时间类型适配。
.NET & EntityFramwork 驱动的适配
参考文档:https://help.aliyun.com/zh/polardb/polardb-for-oracle/net
多版本适配

为了满足客户对不同 .NET 框架版本的需求,PolarDB 采取了全面兼容的策略,实现了从 .NET Framework 2.0 至的 .NET Framework 7.0的全兼容,以及跨平台的 .NET Core 和跨库兼容的 .NET Standard 版本的适配。这项技术成就确保了客户能够在各种 .NET 环境中无缝完成驱动的替换,全面保障了业务的持续性和技术的前沿性。
数据类型适配
本节主要介绍业务系统在EntityFramwork框架中的适配问题。

实体层(Entity Layer):在实体定义中,用户指定 TypeName 为 "DATE",这样做声明了表结构中的时间字段应映射为数据库的抽象 DATE 类型。 上下文层(DbContext Layer):在 DbContext 中,为 DATE 类型定义了一个内存中的表示。为适应不同的数据库驱动,这个类型需要有针对性的实现。对于 PolarDB 的 .NET 驱动,必要的工作是将实体的 DATE 类型映射为数据库中的 64 位 date 类型。 数据库层(Database Layer):在数据库端,PolarDB 提供了 DATE 类型的完整的 64 位实现,这确保了数据表中的时间字段保持了和 Oracle 中相同的精度。
通过这样的梯次化适配,业务用户对 DATE 类型的使用变得透明无感,无论后端数据库是 Oracle 还是 PolarDB。这种无缝适配策略最大程度地减少了迁移和适配过程中对现有业务的影响,确保了数据类型表示的一致性和准确性。
DTS保障数据实时迁移和一致性
数据迁移、校验流程

结构迁移
全量迁移
增量日志解析和数据回放
全量数据校验
增量数据校验
反向回流和增量校验
在应用停写后、应用割接切流前建立反向回流链路,启动增量数据反向回流,提供割接失败之后能回切到Oracle数据库的能力。
数据迁移
采样切片保障全量迁移性能和稳定性
采样切片仅做一次查询,使用数据库sample函数进行采样,保障切片效率和大表迁移稳定性,解决Oracle临时表空间膨胀问题,提供表内并发写入能力,提高全量迁移效率。原理如下:

实现multi-verison-meta日志解析能力

校验

一主多读架构高效承载流量压力

在应对日益增长的客户流量需求时,PolarDB采取了一种高度优化且策略性的一写一读部署架构,这一设计遵循了读写分离的原则,从而实现了资源利用的最大化与服务性能的显著提升。
主从数据库读写分离
主数据库作为整个架构的中枢,专精于处理高并发的在线交易事务,如订单处理等即时操作。通过采用先进的锁机制与事务管理策略,它确保了数据的一致性与事务的ACID特性(原子性、一致性、隔离性、持久性),即便在面对尖峰流量时也能维持极低的延迟响应。主从数据库的配置,为系统的分析处理能力提供了强大的支撑。通过对主库的数据实时复制,从库拥有近乎完整的数据副本,能够独立承担起报表生成、大数据分析、业务趋势预测等分析型工作负载。这种设计不仅充分利用了数据库的读取扩展性,还通过智能调度算法,根据查询类型和资源占用情况自动分发任务,实现了查询效率与资源使用的最优化。

主数据库的单日流量图(示例)

从数据库的单日流量图(示例)
从上图中的监控示例中可以看出,主从数据库负载了主要的流量,读写分离有效分摊了业务的压力。
资源调度优化


全方位的自动化监控
概述
PolarDB-PG还支持使用全局自动负载信息库(Global Automatic Workload Repository,简称GAWR)对数据库进行全方位多维度的监控。如下图所示,监控指标涵盖CPU、内存、I/O、文件系统、TPS、连接数、缓存命中率、延迟、慢SQL等多个维度,基于这些指标可以对数据库系统问题进行详细分析。

(此面板为演示数据,非用户实例数据)
读写IO情况

I/O读写延迟常常反映了当前磁盘带宽和延迟的实际表现,它是评估PolarDB在基于PSL4与PSL5磁盘架构下对负载响应的关键指标。通过对比这两者,我们能够衡量不同硬件配置下的读写延迟影响。(具体细节参考阿里云帮助文档)
TOP 锁阻塞情况

锁阻塞状况是诊断数据库事务瓶颈的关键指标,它为数据库管理员(DBA)提供了洞察当前事务处理性能并采取针对性解决措施的依据。正如所示图表中,该数据库目前存在数个transactionid 类型的锁,这暗示着事务之间发生了因行锁引起的冲突(如并发场景下多个事务尝试更新同一行数据)。




