暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB_PG 迁移至 OB_Oracle 的开源方案

270

作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 2400 字,预计阅读需要 8 分钟。




报名即将截止!瓜分 10 万奖金!OceanBase 首届 AI 黑客松等你来战


1. 背景

客户存在将 PolarDB PostgreSQL[1] 11.9 (下文以 polardb_pg  代称) 迁移至 OceanBase[2] 4.2.1.10 Oracle (下文以 ob_oracle  代称)租户的需求。

当前 OMS[3] 暂不支持此功能,需要人工迁移,本文将描述迁移的整体思路以及相关的问题处理,为异构数据库之间的迁移方案设计提供参考。

PolarDB PostgreSQL 版本是在 PostgreSQL 数据库的基础上构建的,下文的部分处理步骤会将其视作 PostgreSQL 看待。

2. 步骤概览

迁移范围

表结构 + 全量数据迁移 + 全量数据校验

迁移步骤分工

dbcat[4] 版本:2.1.1

dbcat 可转换的对象范围(polardb_pg -> ob_oracle):表结构、视图、序列,其他对象暂不支持。

  • 用户迁移:人工创建
  • 角色迁移:脚本处理
  • 权限迁移:脚本处理
  • 表结构迁移:dbcat 工具
  • 视图迁移:dbcat 工具
  • 序列迁移:dbcat 工具
  • 外键迁移:dbcat 工具 + 脚本处理
  • 其他对象迁移:业务侧自行迁移
  • 数据迁移:DataX[5]
  • 数据校验:脚本处理

3. 用户迁移

  1. polardb_pg 的一个用户可以对应多个 schema。
  2. ob_oracle 租户的一个用户只能对应一个 schema(即,用户名就是 schema)。
  3. 当 polardb_pg 迁移至 ob_oracle 时,一般而言,polardb_pg 端的 schema_name = ob 端的用户名。
    • 特殊项: PUBLIC 等 OB 端默认角色不可作为 OB 端的用户名,需改成新的用户名。
  4. polardb_pg 待迁移用户拥有的角色也需要迁移至 ob_oracle 端。

4. 权限转换

ob_oracle 端权限[6] 分为"对象权限"和"系统权限"两大类,而 polardb_pg 端权限[7] 分类则更多一些。

权限转换思路

  1. 相同的权限无需转换,直接授权即可。
  2. polardb_pg 端特有的权限,在 ob_oracle 端授予相近的权限,或组合权限以实现对应的功能。
    • 比如 polardb_pg 端的 TRUNCATE 权限,在 ob_oracle 端则是用户拥有表的 DROP 权限就可以进行 TRUNCATE TABLE 操作。

5. 表结构转换

5.1 dbcat 转换效率提升

请根据机器实际内存进行调整。

  1. -Xms8G
    :初始堆内存为 8GB。
  2. -Xmx16G
    :最大堆内存为 16GB。
[root@evan_zheng-server bin]# grep Xms dbcat
JAVA_OPTS="$JAVA_OPTS -Xms8G -Xmx16G -XX:+UseG1GC -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M"

5.2 引号问题

5.2.1 问题描述

  1. dbcat 转换默认会将 库名、表名、列名、约束名 带上双引号。
  2. 若在 ob_oracle 端执行 DDL 带上双引号会严格保留双引号中指定的格式(包括大小写),可能导致执行 SQL 时发生找不到表、列等问题。

5.2.2 解决方法

dbcat 转换时加上 --no-quote
 可以产生不带引号的 DDL 语句,示例如下:

dbcat convert -H 10.186.64.61 -P 5432 -u $pg_user -p $password -D postgres --schema $schema --from pgsql11 --to oboracle420 --no-quote --table '*' -f dbcat_path > dbcat_all_tables_$(date +%Y%m%d_%H%M%S).log 2>&1

5.3 外键

5.3.1 问题描述

dbcat 表结构转换时外键与表结构同时生成在一个文件,外键不应在数据迁移前创建,会导致数据迁移出错。

5.3.2 解决方法

将外键从表结构文件中提取并保存到其他文件。

方式一:若外键数量少,且关联的表数据量小,在迁移完数据之后可以直接进行创建,示例如下:

ALTER TABLE $pg_user.$table_name ADD CONSTRAINT "$fk_name" FOREIGN KEY ("$fk_column"REFERENCES $pg_user.$table_name ("$primary_column");

方式二:若外键数量多,且关联的表数据量大,可以通过 ENABLE NOVALIDATE (不检查现有数据是否满足外键条件,新插入或更新的数据必须遵守外键约束。)格式快速创建外键,示例如下:

ALTER TABLE $pg_user.$table_name ADD CONSTRAINT "$fk_name" FOREIGN KEY ("$fk_column"REFERENCES $pg_user.$table_name ("$primary_column"ENABLE NOVALIDATE;

5.4 包含 oid 字段属性的表

5.4.1 问题描述

polardb_pg 存在一种 PostgreSQL数据库 特有的数据类型 oid,包含 oid 字段属性的表无法通过 dbcat 转换,dbcat 在转换表结构时会直接将表忽略,表结构示例如下:

      column_name      |          data_type          | character_maximum_length | is_nullable | column_default |     primary_key     
-----------------------+-----------------------------+--------------------------+-------------+----------------+---------------------
 id                    | character varying           |                       36 | NO          |                | PRIMARY KEY (id)
 content               | oid                         |                          | YES         |                | 
(2 rows)

5.4.2 解决方法

源端将其改造为 bigint 再通过 dbcat 转换。

5.5 基于 oid 创建的索引

5.5.1 问题描述

如下示例中,(oid): 表示索引是基于表的 oid 列创建的。oid 通常是 PostgreSQL 中的一种特殊列类型,用于存储对象的唯一标识符,一般由 PostgreSQL 数据库自动生成。

 schemaname |        tablename         |        indexname        | tablespace |                                             indexdef                         
                    
------------+--------------------------+-------------------------+------------+------------------------------------------------------------------------------
 $schema     | $table_name             | pg_oid_12345_index |            | CREATE UNIQUE INDEX pg_oid_12345_index ON $schema.$table_name USING btree (oid)

5.5.2 解决方法

OceanBase 数据库中没有 oid 这种存储对象的唯一标识符,在 dbcat 转换完的文件中直接移除这一类索引。

5.6 boolean 字段转换

5.6.1 问题描述

dbcat 会将 polardb_pg  中的 boolean 字段转成 ob_oracle  端的 NUMBER(1),polardb_pg  端给 boolean 赋值可能是(t,f,n),迁移数据时,尝试往 NUMBER(1) 插入 (t,f,n)会因为字段属性不符而报错。

5.6.2 解决方法

  1. 在 ob_oracle  目标端将 NUMBER(1) 替换为 CHAR(5) 以提高字段兼容性
  2. 程序代码需做调整,比如原本查询语句是:
select id from table1 where flag = t;

需改成(加上单引号):

select id from table1 where flag = 't';

6. DataX 数据迁移

6.1 DataX 迁移效率提升

6.1.1 DataX 配置参数

请根据机器实际内存进行调整。

  1. -Xms16g
    :初始堆内存为 16GB。
  2. -Xmx32g
    :最大堆内存为 32GB。
grep "DEFAULT_JVM" opt/module/datax/bin/datax.py | grep "Xms"
DEFAULT_JVM = "-Xms16g -Xmx32g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s/log" % (DATAX_HOME)

6.1.2 DataX  json 配置参数

  1. 参数根据实际调整,关键配置作出注释。
  2. 有主键的表需指定 splitPK。

特殊事项:联合主键不符合 json 文件格式,需当作无主键表迁移。

{
    "job": {
        "setting": {
            "speed": {
                // 控制数据传输速度
                "channel"32// 并发通道(线程)数;值越大并行度越高,但可能增加资源压力
            },
            "errorLimit": {
                "record"1000// 允许的最大错误记录数,超过则作业失败
                "percentage"0// 允许的错误记录百分比(0 表示不按百分比限制)
            }
        },
        "content": [
            {
                "reader": {
                    // 数据源(读取数据)的配置
                    "name""postgresqlreader",
                    "parameter": {
                        "username""$pg_user",
                        "password""$password",
                        "column": ["id""version"],
                        "connection": [
                            {
                                "table": ["$schema.$table_name"],
                                "jdbcUrl": ["jdbc:postgresql://10.186.64.61:5432/postgres?useUnicode=true&characterEncoding=utf8"]
                            }
                        ],
                        "splitPK""id"// 数据分片主键,用于并行读取(按 id 分片)
                    }
                },
                "writer": {
                    // 数据目标(写入数据)的配置
                    "name""oceanbasev10writer",
                    "parameter": {
                        "obWriteMode""insert",
                        "column": ["id""version"],
                        "connection": [
                            {
                                "table": ["$table_name"],
                                "jdbcUrl""jdbc:oceanbase://10.186.64.161:2883/$schema_name?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true"// OceanBase JDBC 连接字符串,包含批量操作优化参数
                            }
                        ],
                        "username""SYS@ora_tenant#cluster",
                        "password""$password",
                        "writerThreadCount"10// 写入线程数,控制写入并行度
                        "batchSize"1000// 每批次写入的记录数,优化性能
                        "memstoreThreshold""0.9"
                    }
                }
            }
        ]
    }
}

6.2 数据迁移异常时的处理机制

6.2.1 问题描述

本文的数据迁移任务,分为主任务和多个子任务,主任务是所有需迁移的表的汇总项,子任务是每个表一个任务,启动主任务之后会自动拉起子任务,子任务会按照配置文件依次执行。

DataX 迁移数据时存在某些数据无法迁移,但是不会报错终止任务而是反复重试的行为,这会导致持续打印无效日志占用空间,且阻碍后续任务运行。

6.2.2 解决方法

引入监控脚本,在 OB 端间隔一秒查询一次当前迁移的表和行数,当发现当前迁移的表 5 分钟内行数没有变化时,会自动 kill 掉对应的子任务进程并记录到日志,示例如下:

[2025-04-17 10:23:18] ------------------------
[2025-04-17 10:23:24] 开始检查
[2025-04-17 10:23:24] 总表数量: 4454
[2025-04-17 10:23:24] 当前表: $table_name
[2025-04-17 10:23:24] 第 4228 个表
[2025-04-17 10:23:24] (OB数据库)查询记录数: 0
[2025-04-17 10:23:24] 检查表行数和kill卡住的表_脚本执行剩余时间: 55小时 11分钟

7. 性能监控

  1. PolarDB PostgreSQL 数据库的平台监控。
  2. OceanBase 数据库的 OCP 平台监控。
  3. 主机资源监控。

8. 结论

  1. 异构数据库迁移需考虑两者差异性,测试环境中进行方案验证,再在生产环境进行实施和优化,建议生产环境至少进行一至两轮模拟迁移之后再正式进行割接。
  2. 非增量迁移,为保证数据一致性,停业务并锁定两端用户后再迁移数据。
参考资料
[1] 

PolarDB PostgreSQL 版: https://www.aliyun.com/product/apsaradb/polardbpg

[2] 

OceanBase 企业版: https://www.oceanbase.com/product/oceanbase

[3] 

OceanBase Migration Service: https://www.oceanbase.com/product/oms

[4] 

dbcat: https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-1000000000749015

[5] 

DataX: https://github.com/alibaba/datax

[6] 

ob_oracle 端权限: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220864

[7] 

polardb_pg 端权限: https://help.aliyun.com/zh/polardb/polardb-for-oracle/warpaman72ax09gk


报名即将截止!瓜分 10 万奖金!OceanBase 首届 AI 黑客松等你来战


本文关键字:#OceanBase# #PolarDB# #数据迁移# #dbcat# #DataX#





带宽被 OBServer 备份 “榨干”,集群陷入 “无主” 危机
一文搞懂 OceanBase 4.x 全链路追踪
OBLogProxy 在 Binlog 模式下的故障案例解析
计算 OceanBase 可用 CPU 的核心逻辑


✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle


文章转载自爱可生开源社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论