如何通过 Apache SeaTunnel 实现 MySQL 到 OceanBase的数据迁移同步

本文来源于 OceanBase 数据库官方博客,目前 Apache SeaTunnel 2.3.9 已支持本文提到的所有功能,故原文2.3.7已全部修改为2.3.9

准备传输工具

本方案采用 Apache SeaTunnel(简称SeaTunnel)进行MySQL 到 OceanBase 的数据迁移和同步,出于对方案轻量性的考量,我们采用其内置的 Zeta 引擎来实现,包括全量同步、离线增量同步,以及 CDC 方案。

运行环境准备

自行安装运行环境JAVA,推荐版本为8,但理论上高于8的版本也能正常工作。

安装后,请确保已正确配置JAVA_HOME

root:~# java -version
openjdk version "17.0.12" 2024-07-16
OpenJDK Runtime Environment (build 17.0.12+7-Debian-2deb11u1)
OpenJDK 64-Bit Server VM (build 17.0.12+7-Debian-2deb11u1, mixed mode, sharing)java

下载并安装SeaTunnel

进入官网下载页面,下载适合版本SeaTunnel : https://seatunnel.apache.org/

我这里选择最新版本2.3.9

下载
wget https://dlcdn.apache.org/seatunnel/2.3.9/apache-seatunnel-2.3.9-bin.tar.gz
解压
tar -zxvf apache-seatunnel-2.3.9-bin.tar.gz 

连接器插件的下载与安装

SeaTunnel 安装包只包含主体文件与 Zeta 引擎,连接不同数据源的插件需要手动下载并配置。

自动下载方案

通过配置config/plugin_config文件来指定你需要的连接器,默认文件里是全方案的,可以根据你的需要增删一些,我们这里只包含这次演示需要使用的连接库。

connector-cdc-mysql
connector-jdbc
connector-fake
connector-console

输入命令

sh bin/install-plugin.sh 2.3.9

开始自动下载连接器

手动下载方案

进入网站:https://repo.maven.apache.org/maven2/org/apache/seatunnel/

找到自己需要的插件例如:

connector-cdc-mysql-2.3.9.jar
connector-console-2.3.9.jar
connector-fake-2.3.9.jar
connector-jdbc-2.3.9.jar
seatunnel-transforms-v2-2.3.9.jar

将文件手动下载之后 放入Connectors

验证连接器安装情况
./bin/seatunnel-connector.sh -l
 
Source
FakeSource MySQL-CDC Jdbc
 
 
Sink
Jdbc Console
 
 
Transform
Copy DynamicCompile FieldMapper Filter FilterRowKind JsonPath LLM Replace Split Sql

由于我们是使用 JDBC 使用 MySQL 的连接方式去操作 OceanBase 所以还需要下载一个jdbc-mysql,请自行前往前往 MySQL 官网下载 JDBC 。

将下载的mysql-connector-j-9.0.0.jar放到{seatunnel/lib}中。

SeaTunnel验证

使用 config 官方自带的v2批操作验证 SeaTunnel 是否正常

./bin/seatunnel.sh --config ./config/v2.batch.config.template -m local
 
参数解释:
seatunnel.sh #seatunnel标准启动脚本
config #选择配置脚本
m #运行方式 这里选择本地运行

当您运行该命令时,可以在控制台中看到它的输出

2022-12-19 11:01:45,417 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - output rowType: name<STRING>, age<INT>
2022-12-19 11:01:46,489 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=1:  SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: CpiOd, 8520946
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=2: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: eQqTs, 1256802974
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=3: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: UsRgO, 2053193072
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=4: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: jDQJj, 1993016602
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=5: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: rqdKp, 1392682764
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=6: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: wCoWN, 986999925
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=7: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: qomTU, 72775247
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=8: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: jcqXR, 1074529204
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=9: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: AkWIO, 1961723427
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=10: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: hBoib, 929089763
2022-12-19 11:01:46,490 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=11: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: GSvzm, 827085798
2022-12-19 11:01:46,491 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=12: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: NNAYI, 94307133
2022-12-19 11:01:46,491 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=13: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: EexFl, 1823689599
2022-12-19 11:01:46,491 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=14: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: CBXUb, 869582787
2022-12-19 11:01:46,491 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=15: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: Wbxtm, 1469371353
2022-12-19 11:01:46,491 INFO  org.apache.seatunnel.connectors.seatunnel.console.sink.ConsoleSinkWriter - subtaskIndex=0 rowIndex=16: SeaTunnelRow#tableId=-1 SeaTunnelRow#kind=INSERT: mIJDt, 995616438

并且结尾有一个 Job 总结日志

***********************************************
           Job Statistic Information
***********************************************
Start Time                : 2024-08-29 22:45:29
End Time                  : 2024-08-29 22:45:33
Total Time(s)             :                   4
Total Read Count          :                  32
Total Write Count         :                  32
Total Failed Count        :                   0
***********************************************

全量同步

测试表创建

创建两张一模一样的表 表结构如下:
CREATE TABLE `table1` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `value1` VARCHAR(255) NOT NULL,
    `value2` VARCHAR(255) ,
    `value3` VARCHAR(255) ,
    `value4` VARCHAR(255) ,
    `value5` VARCHAR(255) ,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `idx_value1` (`value1`),
    INDEX `idx_value2_value3` (`value2`, `value3`),
    INDEX `idx_value3_value4_value5` (`value3`, `value4`, `value5`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
CREATE TABLE `table2` (
    `id` INT NOT NULL AUTO_INCREMENT,
    `value1` VARCHAR(255) NOT NULL,
    `value2` VARCHAR(255) ,
    `value3` VARCHAR(255) ,
    `value4` VARCHAR(255) ,
    `value5` VARCHAR(255) ,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `idx_value1` (`value1`),
    INDEX `idx_value2_value3` (`value2`, `value3`),
    INDEX `idx_value3_value4_value5` (`value3`, `value4`, `value5`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们这边使用 navicat 创建了各100000条数据

全量同步配置文件编写

表结构建议手动迁移,自动迁移的表结构会有一些问题,并且不会附加索引。

单表全量
env {
  parallelism = 5
  job.mode = "BATCH"
}
source {
    Jdbc {
        url = "jdbc:mysql://127.0.0.1:3306/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        connection_check_timeout_sec = 100
        user = "xxx"
        password = "xxx"
        query = "select * from seatunnel.table1"
    }
}
sink {
    jdbc {
        url = "jdbc:mysql://127.0.0.1:2883/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        user = "xxx@xxx"
        password = "xxx"
        # 自动判断sql语句
        generate_sink_sql = true
        database = seatunnel
        table = table1
    }
}

结果

  ***********************************************
             Job Statistic Information
  ***********************************************
  Start Time                : 2024-08-30 15:05:39
  End Time                  : 2024-08-30 15:05:47
  Total Time(s)             :                   8
  Total Read Count          :              100000
  Total Write Count         :              100000
  Total Failed Count        :                   0
  ***********************************************
多表全量抽取
env {
  parallelism = 5
  job.mode = "BATCH"
}
source {
    Jdbc {
        url = "jdbc:mysql://127.0.0.1:3306/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        connection_check_timeout_sec = 100
        user = "xxx"
        password = "xxx"
    table_list = [
      {
      table_path = "seatunnel.table1"
      },
      {
      table_path = "seatunnel.table2"
      query = "select * from seatunnel.table2 where id > 100"
      }
    ]
    }
}
sink {
    jdbc {
        url = "jdbc:mysql://127.0.0.1:2883/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        user = "xxx@xxx"
        password = "xxx"
        # 自动判断sql语句
        generate_sink_sql = true
        database = seatunnel
    table_list = ["seatunnel.table1","seatunnel.table2"]
    }
}

结果

  ***********************************************
             Job Statistic Information
  ***********************************************
  Start Time                : 2024-08-30 15:10:09
  End Time                  : 2024-08-30 15:10:20
  Total Time(s)             :                  10
  Total Read Count          :              200000
  Total Write Count         :              200000
  Total Failed Count        :                   0
  ***********************************************

增量同步配置文件编写

对于增量同步,简单的方法是在文件编写时,通过 Query 编写 id 或 updatetime 做增量。

env {
  parallelism = 1
  job.mode = "BATCH"
}
source {
    Jdbc {
        url = "jdbc:mysql://127.0.0.1:3306/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        connection_check_timeout_sec = 100
        user = "xxx"
        password = "xxx"
        query = "SELECT * FROM seatunnel.table1 WHERE updatetime > '2024-01-01' "
    }
}
sink {
    jdbc {
        url = "jdbc:mysql://127.0.0.1:2883/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        user = "xxx@xxx"
        password = "xxx"
        generate_sink_sql = true
        database = seatunnel
        table = table1 
    }
}

在输出端的时候会根据主键进行插入与更新操作,但是这种需要从每次配置配置文件的方案比较繁琐,我更加推荐使用 Apache DolphinScheduler 配合 SeaTunnel 进行操作创建一个工作流。

从输出端获取最大时间或者 id 通过 DolphinScheduler 的工作流变量进行传输。

env {
  parallelism = 1
  job.mode = "BATCH"
}
source {
    Jdbc {
        url = "jdbc:mysql://127.0.0.1:3306/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        connection_check_timeout_sec = 100
        user = "xxx"
        password = "xxx"
        query = "SELECT * FROM seatunnel.table1 WHERE updatetime > ${max_id} "
    }
}
sink {
    jdbc {
        url = "jdbc:mysql://127.0.0.1:2883/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        user = "xxx@xxx"
        password = "xxx"
        generate_sink_sql = true
        database = seatunnel
        table = table1 
    }
}

多表方案同上

CDC同步配置文件编写

手动同步表结构

由于 SeaTunnel 的 oceanbase 组件还是有所问题,表结构同步 遇到报错比较麻烦,这一步还是手动同步。

检查MySQL Binlog状态

赋予用户所需权限

mysql> GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user' IDENTIFIED BY 'password';
 
mysql> FLUSH PRIVILEGES;

检查binlog日志是否开启

mysql> show variables where variable_name in ('log_bin', 'binlog_format', 'binlog_row_image', 'gtid_mode', 'enforce_gtid_consistency');
+--------------------------+----------------+
| Variable_name            | Value          |
+--------------------------+----------------+
| binlog_format            | ROW            |
| binlog_row_image         | FULL           |
| enforce_gtid_consistency | ON             |
| gtid_mode                | ON             |
| log_bin                  | ON             |
+--------------------------+----------------+
5 rows in set (0.00 sec)

如果不一致 请自行更改mysql.cnf文件。

在大型数据库创建一致性快照时,可能会存在读超时,请合理配置!

interactive_timeoutwait_timeout

在处理完准备工作之后编写配置文件。

env {
  parallelism = 1
  job.mode = "STREAMING"
  checkpoint.interval = 10000
}
 
source {
  MySQL-CDC {
    base-url = "jdbc:mysql://127.0.0.1:3306/mysql"
    username = "xxx"
    password = "xxx@xxx"
    table-names = ["seatunnel.table1", "seatunnel.table2"]
    
    startup.mode = "initial"
  }
}
 
sink {
    jdbc {
        url = "jdbc:mysql://127.0.0.1:2883/mysql?&useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true"
        driver = "com.mysql.cj.jdbc.Driver"
        user = "xxx@xxx"
        password = "xxx"
        database = "seatunnel"  # 目标数据库
        table-names = ["seatunnel.table1", "seatunnel.table2"]
        generate_sink_sql = true     # 自动生成 SQL
    }
}

正常启动之后会进行历史数据迁移,再进行 CDC 变更。

注意:

启动之后会根据配置的表和startup.mode选择的模式进行不同的操作。

startup.mode操作如下: initial 启动时同步历史数据,然后同步增量数据earliest ,从最早的偏移量启动 latest 从最新偏移量启动specific,从用户提供的特定偏移量启动。

如果使用specific,需要添加startup.specific-offset.file binlog文件名startup.specific-offset.pos binlog偏转量。

本文完!

<think>好的,我现在需要解决用户关于如何将SQL Server数据库迁移到OceanBase的问题。首先,我需要回顾用户提供的引用内容,虽然这些引用主要是关于MySQLOceanBase的迁移,但可能有一些通用的方法或工具可以参考。 用户提供的引用中提到使用mysqldump和DataX进行迁移。但SQL Server和MySQL不同,所以可能需要不同的工具。首先,我应该考虑SQL Server的导出工具,比如SQL Server自带的bcp或者SSIS(SQL Server Integration Services)。另外,是否有第三方工具支持SQL Server到OceanBase的迁移? 接下来,我需要考虑OceanBase的兼容性。OceanBase兼容MySQL协议,但SQL Server使用的T-SQL和MySQL的SQL语法有差异,所以在迁移过程中需要进行语法转换。这可能涉及到表结构转换、数据类型映射、存储过程和函数的调整等。 然后,迁移步骤可能包括数据导出、转换、导入三个阶段。对于数据导出,可以使用SQL Server的导出功能或第三方工具。转换阶段可能需要手动调整DDL语句,或者使用ETL工具进行处理。导入阶段可能需要使用OceanBase的客户端工具或者类似DataX这样的数据同步工具。 另外,用户可能关心迁移的最佳实践,比如如何保证数据一致性、如何处理迁移过程中的性能问题、是否有增量迁移的方案等。还需要考虑迁移后的验证步骤,确保数据完整性和业务功能正常。 可能的工具方面,除了DataX,是否有其他开源或商业工具支持SQL Server到OceanBase?例如,可以使用Apache NiFi或者定制化的脚本。此外,是否需要中间存储,比如先将数据导出为CSV或SQL文件,再导入到OceanBase? 还需要注意OceanBase的版本和兼容性,不同版本可能对SQL语法的支持不同。用户可能需要调整SQL Server的DDL语句以适应OceanBase的要求。例如,SQL Server的某些数据类型在OceanBase中可能需要替换为兼容的类型,或者修改索引和约束的定义。 最后,确保迁移过程有备份和回滚计划,以防迁移失败或数据丢失。测试迁移也是重要的一环,可以在测试环境中先行验证整个流程,确保无误后再进行生产环境的迁移。</think>### SQL Server迁移至OceanBase的方案与工具指南 #### 一、迁移方法与工具选择 1. **全量迁移工具** - **SQL Server原生工具** 使用`bcp`(Bulk Copy Program)或`SQL Server Management Studio (SSMS)`导出数据为CSV或SQL脚本,再通过OceanBaseMySQL客户端导入。 *示例导出命令*: ```bash bcp [数据库名].[schema].[表名] out "导出文件路径" -S 服务器地址 -U 用户名 -P 密码 -c ``` - **第三方ETL工具** - **DataX**:通过定制`SQLServerReader`和`OceanBaseWriter`插件实现迁移[^2]。 - **Apache NiFi**:支持通过图形化界面配置SQL Server到OceanBase的数据流。 2. **增量同步工具** - **Debezium + Kafka**:通过CDC(Change Data Capture)捕获SQL Server的增量变更,写入Kafka后由消费者同步OceanBase[^1]。 3. **商业工具** - **AWS DMS**:支持异构数据库迁移,需配置SQL Server为源、OceanBase(通过MySQL兼容接口)为目标。 #### 二、迁移步骤详解 1. **结构迁移** - **DDL转换**: SQL Server的`nvarchar(max)`需转为OceanBase的`text`,`datetime2`转为`datetime(6)`。 *示例转换*: ```sql -- SQL Server CREATE TABLE dbo.orders (id INT PRIMARY KEY, note NVARCHAR(MAX)); -- OceanBase CREATE TABLE orders (id INT PRIMARY KEY, note TEXT); ``` - **工具辅助**: 使用`SQLines`或`AWS SCT`自动化转换DDL语句。 2. **数据迁移** - **全量迁移流程**: ```mermaid graph LR A[SQL Server导出CSV] --> B[数据清洗] B --> C[OceanBase LOAD DATA导入] ``` - **DataX任务配置**: ```json { "job": { "content": [{ "reader": { "name": "sqlserverreader", "parameter": {"connection": [{"jdbcUrl": "jdbc:sqlserver://ip:port", "table": ["dbo.table1"]}]} }, "writer": { "name": "oceanbasev10writer", "parameter": {"connection": [{"jdbcUrl": "obclient://user@ip:port/db", "table": ["table1"]}]} } }] } } ``` 3. **验证与回滚** - **数据一致性校验**: 使用`pt-table-checksum`或自定义脚本对比行数、哈希值。 - **回滚策略**: 保留SQL Server全量备份至少7天,通过`FLASHBACK`快速恢复OceanBase数据。 #### 三、最佳实践 1. **性能优化** - 分批次导入:设置DataX的`batchSize`为5000-10000行/批次[^2]。 - 关闭约束:导入前执行`SET FOREIGN_KEY_CHECKS=0`。 2. **兼容性处理** - **函数替换**: SQL Server的`GETDATE()`改为OceanBase的`NOW()`。 - **存储过程重写**: 将T-SQL的`OUTPUT`参数逻辑改为MySQL兼容的`SELECT...INTO`语法。 3. **增量同步配置** Debezium连接器示例: ```properties connector.class=io.debezium.connector.sqlserver.SqlServerConnector database.hostname=192.168.1.100 database.port=1433 database.user=sa database.password=**** database.dbname=testdb table.include.list=dbo.orders ``` #### 四、常见问题解决 - **乱码问题**:确保SQL Server的`Collation`与OceanBase的`utf8mb4_general_ci`一致。 - **数据类型不匹配**:使用`CAST`函数强制转换,如`CAST(amount AS DECIMAL(10,2))`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SeaTunnel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值