返回首页

Oracle → PostgreSQL 无停机迁移

从 Oracle 到 PostgreSQL 无服务停机迁移的详细技术详解。使用通过 Debezium 和 Kafka Connect 的 CDC、通过 Liquibase 的模式适配、Java 代码调整、序列同步,以及逐步实施。

如何从 Oracle 迁移到 PostgreSQL 而不中断一分钟
Advertisement 728x90

从 Oracle 迁移到 PostgreSQL 无停机:技术详解

从 Oracle 迁移到 PostgreSQL 而无需停止服务是一项具有挑战性但可实现的任务。本文基于一个真实项目,详细分解了一个逐步迁移策略,该项目使用 Spring Boot 微服务,并将对用户零影响作为关键要求。通过 Debezium 实现的 CDC 实现了实时数据同步,避免了停机并将风险降到最低。

准备阶段:分析结构和数据

第一阶段需要对当前数据库进行深入审计。你需要了解数据量、字段类型分布、过时记录的存在,以及 Oracle 特有的结构,这些在 PostgreSQL 中没有直接等价物。清理无关数据可以减少迁移量并加速进程。

一个关键方面是数据类型映射。例如:

Google AdInline article slot
  • NUMBER(1,0)BOOLEAN
  • VARCHAR2TEXTVARCHAR
  • DATETIMESTAMP WITHOUT TIME ZONE
  • CLOBTEXT

用于分析,我们使用了这个 SQL 查询:

select distinct DATA_TYPE
from ALL_TAB_COLUMNS
where owner = 'schemat'
order by DATA_TYPE

基于结果,我们创建了一个数据类型映射表,这成为后续所有转换的基础。同样重要的是要考虑 NULL 和空字符串的处理差异:在 Oracle 中,空字符串被视为 NULL,但在 PostgreSQL 中不是。这需要调整业务逻辑和查询。

模式适配和 Liquibase

简单替换数据库驱动就会导致错误。迁移脚本必须针对 PostgreSQL 进行适配。为此:

Google AdInline article slot
  • 通过 Liquibase 上下文分离 DDL 和 DML 操作——临时禁用 DML。
  • 迭代测试脚本:每次更改后运行变更日志,然后进行清理和烟雾测试。
  • 验证前提条件的正确性,并确保与 Oracle 的模式一致性。

序列需要特别注意。如果它们不同步,新 ID 可能会与历史数据冲突。解决方案:

  • 应用启动时,检查 PostgreSQL 中的当前序列值。
  • 如果它低于 Oracle 中的值,则向前推进并留出一些缓冲。
  • 该逻辑是幂等的:重复运行不会导致失败。

结果,目标 PostgreSQL 模式在一个拉取请求中组装完成,准备好填充数据。

应用代码调整

在成功针对空 PostgreSQL 启动应用后,Java 层面的代码错误会浮出水面。主要变更:

Google AdInline article slot
  • @Lob 注解替换为 @Column(columnDefinition = "text")
  • 在原生 SQL 查询中处理 NULL,特别是 IN (...) 结构。
  • 从数字标志 (0/1) 切换到 boolean
  • 调整字符串比较逻辑,考虑 Oracle/PostgreSQL 的差异。
  • 为 PostgreSQL 方言重写原生查询。

测试在单元测试和集成场景级别进行。特别关注边缘情况:空字符串、NULL 值、大文本字段。

通过 Debezium 和 Kafka Connect 实现 CDC

我们选择了经典技术栈:Debezium + Kafka Connect。架构:

  • 源连接器 (Debezium Oracle) 读取重做日志并生成 CDC 事件。
  • 事件发送到 Kafka(每个表一个主题)。
  • 接收连接器 (JDBC Sink) 按相同顺序将变更应用到 PostgreSQL。

设置阶段:

  • 初始快照——启动时的全量数据复制。
  • 流式变更——从重做日志连续复制 INSERT/UPDATE/DELETE。
  • 顺序保持——通过 LogMiner 保证变更序列。

使用的镜像:

  • quay.io/debezium/kafka:3.0
  • quay.io/debezium/zookeeper:3.0
  • quay.io/debezium/connect:3.0
  • provectuslabs/kafka-ui:0.7.2(用于监控)

设置通过 REST API 使用 curl 完成。迁移期间 Debezium UI 不稳定,因此配置以 JSON 格式手动传递。

示例源连接器配置:

{
  "name": "oracle-connector",
  "config": {
    "connector.class": "io.debezium.connector.oracle.OracleConnector",
    "database.hostname": "oracle-host",
    "database.port": "1521",
    "database.user": "user",
    "database.password": "password",
    "database.dbname": "ORCLCDB",
    "database.server.name": "server1",
    "table.include.list": "schema.table1,schema.table2",
    "database.history.kafka.bootstrap.servers": "kafka:9092",
    "database.history.kafka.topic": "schema-changes"
  }
}

示例接收连接器配置:

{
  "name": "postgres-sink",
  "config": {
    "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",
    "connection.url": "jdbc:postgresql://postgres:5432/db",
    "connection.user": "user",
    "connection.password": "password",
    "topics": "server1.schema.table1,server1.schema.table2",
    "auto.create": "false",
    "auto.evolve": "false",
    "insert.mode": "upsert",
    "pk.mode": "record_key",
    "pk.fields": "id"
  }
}

有些表(例如具有复合键的表)需要单独配置。每个连接器单独测试。

最终切换和质量控制

完成初始快照并稳定流式传输后:

  • 启动连接到 PostgreSQL 的服务测试实例。
  • 执行端到端测试:API、UI、后台进程。
  • 在类似生产的数据上进行负载测试。
  • 在负载最小时刻,切换 DNS 或入口路由到新实例。
  • 监控 24–48 小时的日志、指标和警报。

回滚仅在切换点之前可能。之后,系统完全运行在 PostgreSQL 上。保留 Oracle 备份以用于紧急数据恢复。

关键经验教训

  • 没有通用的解决方案——每个项目都需要自定义适配。
  • 无双写 CDC——几秒延迟的可接受折衷。
  • 序列同步——防止 ID 冲突的必需步骤。
  • 每个阶段测试——稳定迁移的关键。
  • Debezium + Kafka Connect——在线迁移的灵活可靠技术栈。

迁移过程包括准备在内共耗时 18 小时,但实际用户停机时间为 0 秒。该项目已在 PostgreSQL 上成功运行一年多,没有任何退化。

— Editorial Team

Advertisement 728x90

继续阅读