未验证 提交 bf976761 编写于 作者: O obpilot 提交者: GitHub

Ob quick start chapter04 (#583)

* Add chapter04 tutorial, about 'how to migrate data to or from oceanbase'.

* Update some description about mysqldump,datax
上级 41007070
# 第 4 章:如何迁移 MySQL 数据
OceanBase 社区版兼容 MySQL 数据库常用语法,具体主要是 5.5/5.6 常用语法。数据从 MySQL 迁移到 OceanBase 一般首先需要判断 MySQL 数据库表的类型在 OceanBase 里是否兼容。然后,再根据实际情况使用不同的数据同步技术。
## 本章目录
+ [OceanBase MySQL 兼容性简介](4.1.md)
+ [如何使用 mysqldump 迁移 MySQL 表 OceanBase](4.2.md)
+ [如何使用 dbcat 迁移 MySQL 表结构到 OceanBase](4.3.md)
+ [如何把 MySQL 表数据导出到 CSV 文件](4.4.md)
+ [如何使用 OceanBase 的 LOAD 命令加载 csv 数据文件 OB](4.5.md)
+ [如何使用 DATAX 加载 CSV 数据文件到 OB](4.6.md)
+ [如何使用 DATAX 迁移 MySQL数据到 OceanBase](4.7.md)
+ [如何使用 OBDUMPER / OBLOADER 工具导出/导入 OceanBase 数据](4.8.md)
+ [如何使用 DATAX 迁移 OceanBase 数据到 MySQL/ORACLE](4.9.md)
+ [如何使用 CANAL 将 MySQL 数据实时同步到 OB](4.10.md)
+ [如何使用 LOGPROXY 将 OceanBase 数据实时同步到 MySQL](4.11.md)
+ [如何对 OceanBase 迁移性能进行简单分析和调优](4.12.md)
## 如何联系我们
欢迎广大 OceanBase 爱好者、用户和客户有任何问题联系我们反馈:
+ 社区版官网论坛:[https://open.oceanbase.com/answer](https://open.oceanbase.com/answer)
+ 社区版项目网站提 `Issue`[https://github.com/oceanbase/oceanbase/issues](https://github.com/oceanbase/oceanbase/issues)
+ 钉钉群:群号 `33254054`
\ No newline at end of file
# OceanBase 的 MySQL 兼容性简介
MySQL 兼容性主要看表的数据类型、业务 SQL 的兼容性。
MySQL 的函数、触发器、存储过程 在 OceanBase MySQL 里支持的并不好,也不推荐用。所以本章数据迁移就只包含数据库表对象及其数据的迁移。
## 支持的数据类型
OceanBase 数据库支持的数据类型有:
+ 数值类型
- 整数类型:BOOL/BOOLEAN、TINYINT、SMALLINT、MEDIUMINT、INT/INTEGER、BIGINT
- 定点类型:DECIMAL/NUMERIC
- 浮点类型:FLOAT、DOUBLE
- Bit-Value 类型:BIT
+ 日期时间类型
- DATETIME、TIMESTAMP、DATE、TIME、YEAR
+ 字符类型
- VARCHAR、VARBINARY、CHAR、BINARY、enum、set
+ 大对象类型
- TINYTEXT、TINYBLOB、TEXT、BLOB、MEDIUMTEXT、MEDIUMBLOB、LONGTEXT、LONGBLOB
- OceanBase 的大对象目前大小不能超过 48MB 。
与 MySQL 数据库对比,OceanBase 数据库暂不支持空间数据类型和 JSON 数据类型,其他类别的数据类型除了大对象外,支持情况是等于或大于 MySQL 数据库的。
## 支持的SQL 语法
常用的 SQL 这里主要列举 查询和修改 SQL 。
+ `SELECT`
- 支持大部分查询功能,包括支持单、多表查询;支持子查询;支持内连接、半连接以及外连接;支持分组、聚合;常见的概率、线性回归等数据挖掘函数等
- 支持如下集合操作:
`union``union all``intersect``minus`
- 不支持 `SELECT … FOR SHARE …` 语法
支持通过如下方式查看执行计划:
```sql
EXPLAIN <SQL Statement> \G
EXPLAIN extended_noaddr <SQL Statement> \G
EXPLAIN extended <SQL Statement> \G
```
+ `INSERT`
- 支持单行和多行插入,同时还支持指定分区插入
- 支持 `INSERT INTO … SELECT …` 语句
+ `UPDATE`
- 支持单列和多列更新
- 支持使用子查询
- 支持集合更新
+ `DELETE`
- 支持单表和多表删除
+ `TRUNCATE`
- 支持完全清空指定表
## 支持的变量
MySQL 实例里的参数叫 `variable` 。可以在启动时命令行下设置,也可以在启动的配置文件中设置,或者在 SQL 命令行下设置。SQL 里设置又分为全局级别设置和会话级别设置。
MySQL 有些变量在 OceanBase MySQL 租户里同样适用,但是要留心源端 MySQL 和目标端 OceanBase 这些变量值的差异。
| 变量名 | 变量默认值(OB) | 变量含义 |
|---------------------------|--------------------|----------------------------------------------------------------------------------|
| autocommit | ON | 是否自动提交。ON 表示每个DML后会自动添加 commit 语句;OFF 表示不会自动 commit,需要用户主动 commit 或 rollback 事务。 |
| auto_increment_cache_size | 1000000 | 自增列的缓存值。自增列在节点重启发生切换后可能会跳号,这个值越大,跳号间隔越大。 |
| auto_increment_increment | 1 | 自增列类型值的增长步长 |
| auto_increment_offset | 1 | 自增列类型值的起始值 |
| character_set_client | utf8mb4 | 连接的客户端环境的字符集。保持默认。 |
| character_set_connection | utf8mb4 | 连接自身的字符集。保持默认。 |
| character_set_database | utf8mb4 | 连接的数据库的字符集。保持默认。 |
| collation_connection | utf8mb4_general_ci | |
| collation_database | utf8mb4_general_ci | |
| collation_server | utf8mb4_general_ci | |
| max_allowed_packet | 4194304 | 需要调大,否则 SQL文本或数据量很大的时候可能报错。 |
| sql_mode | STRICT_ALL_TABLES | |
| transaction_isolation | READ-COMMITTED | |
| tx_isolation | READ-COMMITTED | |
| lower_case_table_names | 1 | 1 表示自动将表名转小写,则大小写不敏感。0 表示不对表名大小写转换,则是大小写敏感。 |
| foreign_key_checks | ON | ON:检查外键约束;OFF:不检查外键约束。 |
这些变量中要留意字符集相关设置、`sql_mode` 设置以及 `lower_case_table_names` 设置。这些设置最好是在数据迁移之前就正确设置。后期修改会带来风险。
## 支持的字符集
OceanBase MySQL 租户支持字符集 `gbk``utf8mb4` 。 默认是后者。租户的字符集在租户创建的时候指定,设置的是租户全局级别的字符集。
字符集 `utf8mb4``utf8` 的超集,多一些表情字符的编码。建议迁移到 OceanBase 都使用这个字符集。
`utf8mb4` 字符集下,每个英文字符长度 1 字节,每个汉字 长度 3 字节,每个表情字符长度 4 字节。如果迁移数据换了字符集,字符串列的长度需要适当放长。
```sql
MySQL [test]> create table t1(c1 varchar(50));
Query OK, 0 rows affected (0.04 sec)
MySQL [test]> insert into t1 values('a'),('中');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
MySQL [test]> select length(c1) from t1;
+------------+
| length(c1) |
+------------+
| 1 |
| 3 |
+------------+
2 rows in set (0.01 sec)
```
当从 MySQL 中导出数据时,要确保数据库里的字符都能正确输出到文件中。通过 `vim` 命令下的 `:set fileencoding` 命令可以查看文件的编码。一般建议都是 `utf-8`。这样通过文件迁移 MySQL 数据时就不会出现乱码现象。
# 如何使用 CANAL 将 MySQL 数据实时同步到 OceanBase
CANAL 是 Alibaba 开源的一个产品,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。开源项目地址:`https://github.com/alibaba/canal`
## 工作原理简介
+ `canal` 模拟 `MySQL slave` 的交互协议,伪装自己为 `MySQL slave `,向 `MySQL master` 发送 `dump` 协议。
+ `MySQL master` 收到 `dump` 请求,开始推送 `binary log``slave (即 `canal` ) 。
+ `canal` 解析 `binary log` 对象(原始为 byte 流)。
## 部署 CANAL
## MySQL 准备
+ 对于自建 MySQL , 需要先开启 Binlog 写入功能,配置 `binlog-format` 为 ROW 模式,`my.cnf` 中配置如下。
```bash
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
```
+ 授权 canal 链接 MySQL 账号具有作为 `MySQL slave` 的权限, 如果已有账户可直接 `grant` 。
```sql
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;
```
## 下载启动 CANAL
+ 下载 `canal` ,访问地址:`https://github.com/alibaba/canal/releases` 。
```bash
wget https://github.com/alibaba/canal/releases/download/canal-1.1.5/canal.deployer-1.1.5.tar.gz
```
+ 解压缩
```bash
mkdir /tmp/canal
tar zxvf canal.deployer-$version.tar.gz -C ~/canal
```
解压完成后,进入 /tmp/canal 目录,可以看到如下结构。
```bash
tree -L 3 ~/canal/
```
+ 修改配置
```bash
vi conf/example/instance.properties
# mysql serverId
canal.instance.mysql.slaveId = 1234
#position info,需要改成自己的数据库信息
canal.instance.master.address = 127.0.0.1:3306
canal.instance.master.journal.name =
canal.instance.master.position =
canal.instance.master.timestamp =
#canal.instance.standby.address =
#canal.instance.standby.journal.name =
#canal.instance.standby.position =
#canal.instance.standby.timestamp =
#username/password,需要改成自己的数据库信息
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal
canal.instance.defaultDatabaseName =
canal.instance.connectionCharset = UTF-8
#table regex
canal.instance.filter.regex = .\*\\\\..\*
```
`canal.instance.connectionCharset` 代表数据库的编码方式对应到 java 中的编码类型,比如 `UTF-8`,`GBK` ,` ISO-8859-1` 。
如果系统是1个 cpu,需要将 `canal.instance.parser.parallel` 设置为 `false` 。
+ 启动
```bash
sh bin/startup.sh
```
+ 查看 server 日志
```bash
vi logs/canal/canal.log</pre>
```
+ 查看 instance 的日志
```bash
vi logs/example/example.log
```
+ 关闭
```bash
sh bin/stop.sh
```
## 部署 RDB 适配器
RDB adapter 用于适配mysql到任意关系型数据库(需支持jdbc)的数据同步及导入 。
+ 修改启动器配置: application.yml, 这里以 OceanBase 目标库为例
```bash
canal.conf:
canalServerHost: 127.0.0.1:11111
batchSize: 500
syncBatchSize: 1000
retries: 0
timeout:
mode: tcp # kafka rocketMQ
srcDataSources:
defaultDS:
url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true
username: root
password: 121212
canalAdapters:
- instance: example # canal instance Name or mq topic name
groups:
- groupId: g1
outerAdapters:
- name: rdb # 指定为rdb类型同步
key: oracle1 # 指定adapter的唯一key, 与表映射配置中outerAdapterKey对应
properties:
jdbc.driverClassName: com.mysql.cj.jdbc.Driver # jdbc驱动名, 部分jdbc的jar包需要自行放致lib目录下
jdbc.url: jdbc:mysql:thin:@localhost:2883/tpccdb # jdbc url
jdbc.username: root@obmysql # jdbc username
jdbc.password: 123456 # jdbc password
threads: 5 # 并行执行的线程数, 默认为1
```
+ RDB表映射文件
修改 `conf/rdb/mytest_user.yml` 文件:
```bash
dataSourceKey: defaultDS # 源数据源的key, 对应上面配置的srcDataSources中的值
destination: example # cannal的instance或者MQ的topic
groupId: # 对应MQ模式下的groupId, 只会同步对应groupId的数据
outerAdapterKey: oracle1 # adapter key, 对应上面配置outAdapters中的key
concurrent: true # 是否按主键hash并行同步, 并行同步的表必须保证主键不会更改及主键不能为其他同步表的外键!!
dbMapping:
database: mytest # 源数据源的database/shcema
table: user # 源数据源表名
targetTable: mytest.tb_user # 目标数据源的库名.表名
targetPk: # 主键映射
id: id # 如果是复合主键可以换行映射多个
# mapAll: true # 是否整表映射, 要求源表和目标表字段名一模一样 (如果targetColumns也配置了映射,则以targetColumns配置为准)
targetColumns: # 字段映射, 格式: 目标表字段: 源表字段, 如果字段名一样源表字段名可不填
id:
name:
role_id:
c_time:
test1:
```
导入的类型以目标表的元类型为准, 将自动进行类型转换。
+ Mysql 库间镜像schema DDL DML 同步
修改 `application.yml` :
```bash
canalAdapters:
- instance: example # canal instance Name or mq topic name
groups:
- groupId: g1
outerAdapters:
- name: rdb
key: mysql1
properties:
jdbc.driverClassName: com.mysql.jdbc.Driver
jdbc.url: jdbc:mysql://192.168.0.36/mytest?useUnicode=true
jdbc.username: root
jdbc.password: 121212
```
修改 `conf/rdb/mytest_user.yml` 文件:
```bash
dataSourceKey: defaultDS
destination: example
outerAdapterKey: mysql1
concurrent: true
dbMapping:
mirrorDb: true
database: mytest
```
其中`dbMapping.database` 的值代表源库和目标库的 `schema` 名称,即两库的 `schema` 要一模一样。
+ 启动 RDB
将目标库的`jdbc jar` 包放入lib文件夹。
启动 `canal-adapter` 启动器。
```bash
bin/startup.sh
```
验证 修改 `mysql mytest.user` 表的数据, 将会自动同步到 MySQL 的 `MYTEST.TB_USER` 表下面, 并会打出 DML 的 log 。
# 如何使用 LOGPROXY 将 OB 数据实时同步到 MySQL
<待补充>
\ No newline at end of file
# 如何对 OceanBase 迁移性能进行简单分析和调优
## DataX 的调优建议
DataX 本质上是个数据交换平台,将源端的数据读出,写入到目标端。其数据迁移性能取决于下面几个因素:
+ 源端的读性能。可以加并发,制约条件就是对源库的影响、源库的性能瓶颈等。
+ DataX 自身的性能。DataX 是个Java程序,其能起的线程数也是有限,受限于所在主机的CPU和内存大小。
+ 网络传输性能。并发高的时候,网络传输要留意吞吐量是否达到网卡瓶颈。现在万兆网卡的吞吐量 10000Mb,很难达到。不过占用网络带宽对其他业务可能也会有影响。
+ 目标端的写入性能。也可以加并发,制约条件就是目标库写入性能瓶颈、对目标库的影响等。如果目标端是OB,需要针对OB调优。
+ 涉及到文件数据源的时候,关注文件所在磁盘 IO 性能。如 iops、吞吐量等。
所以 DataX 的调优就是调节 `reader``writer` 的各个并行参数,尽可能的把 源和目标端数据库资源能力都利用上,那么整体 DataX 的迁移效率会最好。
此外,如果主机内存够大的话, `datax.py` 能使用的 JVM 内存也可以调大。编辑脚本,调大 `-Xms``-Xmx` 参数。
```bash
vim bin/datax.py
30 DEFAULT_JVM = "-Xms16g -Xmx16g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s/log" % (DATAX_HOME)
```
## 读写并行度
DataX 的配置文件中首先有 `speed` 的设置,其中 `channel` 是总的并发数。
OB 的 `oceanbasev10writer` 还进一步支持 多线程,通过参数 `"writerThreadCount":10` 指定每个 channel 从源端读取的数据,再分几个并发线程写入。所以OB总的写入并发数是 `channel` * `writerThreadCount`
每个 `writer` 里还有个 batchsize,那个是一个事务的记录数数量。通常建议 200-10000 都可以。尽量不要超过 1万。事务太大了,不是很好。在 OceanBase 里事务太大太长,可能会到达事务超时时间(默认120秒)。
这里有趣的是,OB 的 `oceanbasev10writer` 会把这个batch insert 合并为 一个 insert 多个values 子句。所以 `batchSize` 也不要太大;否则,insert sql 文本太长, 高并发时也可能会报错(内存不足方面的错误)。当列非常多的时候(比如说100 列) 或者 值的内容有大文本的时候,这个 `batchSize` 控制在 几百左右比较好。
## 源端数据库读优化
当源端是数据库的时候,如果表有单列主键,并且主键列类型的 数值型 (如 number、bigint、integer、decimal 等),可以在源端 `reader` 里增加配置 : `"splitPk": "id"` 。这个时候,DataX 能先对主键进行切片,然后多个 channel 同时并发分段去读取源数据。 如果没有这个设置,那源端只能单并发读取数据。
## OB写入的内存调优
OB 的数据读写模型比较特殊,增量都在内存里。当 OceanBase 机器已经是 SSD 盘的时候, IO 不大可能会首先成为 OceanBase 的性能瓶颈,内存和 CPU 更有可能先是瓶颈。大量数据写入的时候,增量对 memtable 内存的消耗会很快。OB 设置不当的情况下,可能会出现内存耗尽,从而写入报错。其他业务写入也会跟着报错。
OB 的内存优化过程比较复杂。这里先给出一个初始的设置,能降低内存写入报错的概率。
```sql
alter system set merge_thread_count = 32; -- 增大合并的线程数。
alter system set minor_merge_concurrency = 16; -- 增大转储的线程数,期望提高转储的速度。
alter system set _mini_merge_concurrency = 8; -- 增大mini_merge的线程数,期望提高mini_merge的速度(默认值为3)。调大为8以后,发现会导致压测中CPU使用率有时飙升至90%,对性能有影响。
alter system set memory_limit_percentage = 90; -- OB占系统总内存的比例,提高OB可用的内存量。
alter system set memstore_limit_percentage = 55; -- memstore占租户的内存比,尽量增大memstore的空间(但是可能对读操作有负面影响)。
alter system set freeze_trigger_percentage = 40; -- 启动major/minor freeze的时机,让转储(minor freeze)尽早启动,memstore内存尽早释放。
alter system set minor_freeze_times = 100; -- minor freeze的次数,尽量不在测试期间触发major freeze。
alter system set minor_warm_up_duration_time = 0; -- 加快minor freeze
```
OB 的 `oceanbasev10writer` 插件也提供参数 `memstoreThreshold` 监测增量内存的利用率,如果到达这个阈值,DataX 自动降速。
OB 的增量内存使用也可以监控,关键 SQL 是:
```sql
SELECT tenant_id, ip, round(active/1024/1024/1024) active_gb, round(total/1024/1024/1024) total_gb, round(freeze_trigger/1024/1024/1024) freeze_trg_gb, round(mem_limit/1024/1024/1024) mem_limit_gb
, freeze_cnt , round((active/freeze_trigger),2) freeze_pct, round(total/mem_limit, 2) mem_usage
FROM `gv$memstore`
WHERE tenant_id =1001
ORDER BY tenant_id, ip;
```
OB 的监控产品里也能监控增量内存的变化。
# 如何使用 mysqldump 迁移 MySQL 表 OceanBase
mysqldump 是 MySQL 提供的用于导出 MySQL 数据库对象和数据的工具,非常方便。
使用帮助详情可以通过 参数 `-h` 查看,功能非常丰富,这里就不再赘述。
这里主要把 `mysqldump` 常用的场景命令参数搭配列举一下。
## 导出指定数据库的表结构(不包括数据)
```bash
mysqldump -h 127.1 -uroot -P3306 -p123456 -d TPCH --compact > tpch_ddl.sql
```
这个导出来的脚本有几个特征:
+ 视图的定义也会在里面,但是会以注释 /*!*/ 。视图我们不关注,这部分内容可以删除。
+ 会有一些特别的语法 OceanBase MYSQL 会不支持,但是不影响,需要替换掉其中部分。
下面这个示例就是到处的脚本里有一个 `MAX_ROWS=` 的设置,这个是 MySQL 特有的,OceanBase MySQL 没有这个问题,也不需要这个设置,不支持这个语法,会报错。
```sql
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `NATION` (
`N_NATIONKEY` int(11) NOT NULL,
`N_NAME` char(25) COLLATE utf8_unicode_ci NOT NULL,
`N_REGIONKEY` int(11) NOT NULL,
`N_COMMENT` varchar(152) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`N_NATIONKEY`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci MAX_ROWS=4294967295;
```
需要把所有 `MAX_ROWS=` 以及后面部分注释掉。使用批量替换技术。如在 `vim` 中使用 `:%s/MAX_ROWS=/; -- MAX_ROWS=/g`
注意:上面导出的 SQL 中表名是大写,说明源端 MySQL 里设置表名默认很可能是大小写敏感。因此目标 OceanBase MySQL 租户也要设置。
在导出的表结构语句里,可能包含外键。在导入 OceanBase MySQL 里时,如果外键依赖的表没有创建时,导入脚本会报错。因此导入之前需要将外键检查约束先禁用掉。
```sql
MySQL [oceanbase]> set global foreign_key_checks=off;
Query OK, 0 rows affected (0.01 sec)
MySQL [oceanbase]> show global variables like '%foreign%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| foreign_key_checks | OFF |
+--------------------+-------+
1 row in set (0.00 sec)
```
修改后,退出会话,重新登录。
在 obclient 客户端里通过 `source` 命令可以执行外部 SQL 脚本文件。
## 导出指定数据库的表数据(不包括结构)
```bash
mysqldump -h 127.1 -uroot -P3306 -p123456 -t TPCH > tpch_data.sql
```
mysqldump 导出的数据初始化 SQL 里会首先将表 LOCK 住,禁止其他会话写。然后使用 `insert` 写入数据。每个 `insert` 后面的 `value` 里会有很多值。这是批量 `insert`
```sql
LOCK TABLES `t1` WRITE;
/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
INSERT INTO `t1` VALUES ('a'),('中');
/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
```
可能还存在其他导致报错的语句这里没有提到,欢迎到 OceanBase 社区版官网问答区反馈 。反馈地址:`https://open.oceanbase.com/answer/`(<https://open.oceanbase.com/answer>) 。
# 如何使用 dbcat 迁移 MySQL 表结构到 OceanBase
DBCAT 是一款轻量级的命令行工具。主要用途是提供 源数据库到 OceanBase MYSQL/ORACLE 的 DDL 转换、`Schema` 比对等功能。文件名是:`dbcat-[版本号]-SNAPSHOT.tar.gz`,下载后解压缩即可使用,可执行文件名是:`dbcat` 。OceanBase 社区版只支持 MySQL 兼容性,所以这里只演示 MySQL 表结构转换。
## 环境准备
DBCAT 能运行在 `CentOS``MacXOS``Windows` 下。需要安装 `JDK 1.8` 以上(含)版本。可以使用 `OpenJDK`,安装好后配置环境变量 `JAVA_HOME`
下面是 CentOS 里安装 `OpenJDK` 示例:
```bash
$sudo yum -y install java-1.8.0-openjdk.x86_64
$which java
/usr/local/java/jdk1.8.0_261/bin/java
echo 'JAVA_HOME=/usr/local/java/jdk1.8.0_261/' >> ~/.bash_profile
```
解压缩安装文件
```bash
tar zxvf dbcat-1.3.0-SNAPSHOT.tar.gz
cd dbcat-1.3.0-SNAPSHOT/
chmod +x bin/dbcat
$tree -L 3 --filelimit 30
.
├── bin
│   ├── dbcat
│   ├── dbcat.bat
│   └── dbcat-debug
├── conf
│   ├── dbcat.properties
│   └── logback.xml
├── docs
│   ├── README.docx
│   ├── README.md
│   └── README.txt
├── LEGAL.md
├── lib [45 entries exceeds filelimit, not opening dir]
├── LICENSE
├── meta
│   └── README
└── NOTICE
5 directories, 12 files
```
| 目录名 | 说明 |
|--------|-------------------|
| bin | 可执行文件目录。 |
| conf | 日志文件配置目录。 |
| lib | 运行时期依赖的包。 |
| meta | 离线转换场景下,导出字典表数据。 |
| ~/output | SQL文件与报告文件。运行时生成。 |
## 在线转换
在线转换是指 DBCAT 能直连源端数据库,将数据库中对象导出。当对象非常多的时候(如超过 1万),这个可能有点慢。
转换命令帮助:`bin/dbcat help convert` ,参数很多,具体请查看使用文档。
```bash
bin/dbcat convert -H <host> -P <port> -u <user> -p <password> -D <database> --from <from> --to <to> --all
bin/dbcat convert -H 127.1 -P 3306 -u root -p 123456 -D tpccdb --from mysql56 --to obmysql2230 --all
```
特别说明:
+ 目前源端 MySQL 版本 只支持 MySQL 5.5/5.6/5.7 。`--from` 只支持 `mysql56``mysql57`
+ 目标端 OceanBase 版本的参数 `--to` 只支持 `obmysql2230``obmysql2250` 。即使是 OceanBase 2.2.7 和 OceanBase 3.1 版本,也可以写成 `obmysql2250`。因为在MySQL 兼容性方面,这些版本的 MySQL 语法是一样的。
运行后的输出文件在用户 `home` 目录下的 `output` 下。
```bash
$tree ~/output/dbcat-2021-09-19-164533/
/home/qing.meiq/output/dbcat-2021-09-19-164533/
├── tpccdb
│   └── TABLE-schema.sql
└── tpccdb-conversion.html
1 directory, 2 files
```
下面示例查看一个表结构在原生 MySQL 里写法 和 OceanBase 里写法。
```sql
MariaDB [tpccdb]> show create table bmsql_customer \G
*************************** 1. row ***************************
Table: bmsql_customer
Create Table: CREATE TABLE `bmsql_customer` (
`c_w_id` bigint(20) NOT NULL,
`c_d_id` bigint(20) NOT NULL,
`c_id` bigint(20) NOT NULL,
`c_discount` decimal(4,4) DEFAULT NULL,
`c_credit` char(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_last` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_first` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_credit_lim` decimal(12,2) DEFAULT NULL,
`c_balance` decimal(12,2) DEFAULT NULL,
`c_ytd_payment` decimal(12,2) DEFAULT NULL,
`c_payment_cnt` bigint(20) DEFAULT NULL,
`c_delivery_cnt` bigint(20) DEFAULT NULL,
`c_street_1` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_street_2` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_city` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_state` char(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_zip` char(9) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_phone` char(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_since` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`c_middle` char(2) COLLATE utf8_unicode_ci DEFAULT NULL,
`c_data` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`c_w_id`,`c_d_id`,`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
1 row in set (0.01 sec)
vim ~/output/dbcat-2021-09-19-164533/tpccdb/TABLE-schema.sql
create table if not exists tpccdb.bmsql_customer (
c_w_id bigint(20) not null,
c_d_id bigint(20) not null,
c_id bigint(20) not null,
c_discount decimal(4,4),
c_credit char(2),
c_last varchar(16),
c_first varchar(16),
c_credit_lim decimal(12,2),
c_balance decimal(12,2),
c_ytd_payment decimal(12,2),
c_payment_cnt bigint(20),
c_delivery_cnt bigint(20),
c_street_1 varchar(20),
c_street_2 varchar(20),
c_city varchar(20),
c_state char(2),
c_zip char(9),
c_phone char(16),
c_since timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
c_middle char(2),
c_data varchar(500),
primary key (c_w_id, c_d_id, c_id)
)
default charset=utf8mb4
default collate=utf8mb4_unicode_ci;
```
# 如何把 MySQL 表数据导出到 CSV 文件
首先需要了解一下 CSV 文件特点。
## CSV 文件简介
CSV 即 `Comma Separate Values`,这种文件格式经常用来作为不同程序之间的数据交互的格式。
CSV 文件需要满足一些要求才有用。
+ 有固定行分隔符,以区分不同的行。通常行分隔符是换行符,但并不总是这样。
+ 有固定列分隔符,以区分不同的列。默认列分隔符前后的空格会忽略掉。
+ 如果列的内容里出现行分隔符、列分隔符,则会做`转义` 处理。否则,就不能正确识别列或者行。
下面用一个典型的例子来加深对 CSV 文件的印象。
```sql
create table t1(id bigint not null auto_increment, c1 char(10), c2 varchar(10), primary key(id));
insert into t1 (c1, c2) values(' 中 国 ',' 中 国 ');
insert into t1 (c1, c2) values(' 中,国 ',' "中 国" ');
insert into t1 (c1, c2) values(' 中
国 ','中
国 ');
insert into t1 (c1, c2) values(' 中\\国 ',' "中\\国" ');
MariaDB [test]> select * from t1;
+----+----------+-------------+
| id | c1 | c2 |
+----+----------+-------------+
| 1 | | |
| 2 | , | "中 国" |
| 3 |
|
|
| 4 | 中\国 | "中\国" |
+----+----------+-------------+
4 rows in set (0.00 sec)
MariaDB [test]> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | |
+------------------+-------+
1 row in set (0.01 sec)
```
`secure_file_priv` 为空表示不限制导出导入,可以修改 MySQL 的启动参数文件(默认是 `/etc/my.cnf`),添加 `secure_file_priv=/tmp` 。然后重启 MySQL 。
```sql
MariaDB [test]> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | /tmp/ |
+------------------+-------+
1 row in set (0.00 sec)
MariaDB [test]> select * from t1 into outfile '/tmp/t1.csv' fields terminated by ',' enclosed by '"' lines terminated by '\n' ;
Query OK, 3 rows affected (0.00 sec)
```
如果你不指定 FIELDS 或 LINES ,缺省值为:
```sql
FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING BY ''
```
查看这个导出文件 `/tmp/t1.csv` 看看。(通常在这个目录能找到文件,个别比较老的系统,使用 `systemd` 的 CentOS 里的 Mariadb 5.5 的环境下,这个目录下找不到文件。文件实际在 `/tmp/systemd-private-55b199ca1f6f42dfad8bfa065113e790-mariadb.service-EFJMNX/tmp/`下)
```bash
#cat -n tmp/t1.csv
1 "1"," 中 国"," 中 国 "
2 "2"," 中,国"," \"中 国\" "
3 "3"," 中\
4 国","中 \
5 国 "
6 "4"," 中\\国"," \"\\\" "
```
从导出文件里可以看出,字段的值被双引号封装起来了,所以字段里面有分隔符都不要紧。但是字段里面如果包含双引号,就要被默认转义掉,转义引导符是默认的 `\` 。字段里面有换行符也不要紧。
在 MySQL 里再导入这个文件看看。
```sql
MariaDB [test]> create table t2 like t1;
Query OK, 0 rows affected (0.01 sec)
MariaDB [test]> load data infile '/tmp/t1.csv' into table t2 fields terminated by ',' enclosed by '"' lines terminated by '\n' ;
Query OK, 3 rows affected (0.00 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0
MariaDB [test]> select * from t2;
+----+----------+-------------+
| id | c1 | c2 |
+----+----------+-------------+
| 1 | 中 国 | 中 国 |
| 2 | 中,国 | "中 国" |
| 3 | 中
国 | 中
国 |
| 4 | 中\国 | "中\国" |
+----+----------+-------------+
4 rows in set (0.00 sec)
```
MySQL 的 `SELECT INTO OUTFILE` 和 `LOAD DATA` 还有很多高级用法,这个太过复杂,这里就不研究了。通常建议导出和导入使用选项 `fields terminated by ',' enclosed by '"' lines terminated by '\n'` 就可以满足常用需求。至少这样导出的 CSV 文件,能在 MySQL 里导入,那么也应该能在 OceanBase MySQL 里导入,不管是使用方法。
# 如何使用 OceanBase 的 LOAD 命令加载 csv 数据文件 OceanBase
OceanBase MySQL 的 `load data` 命令跟 MySQL 的 `load data` 命令是一样的。这里依然导入上面那个 `t1.csv` 。不同之处,需要把 `csv` 文件放到 OBSERVER 节点机器上。暂时 OceanBase 还不支持加载本地文件,该功能还在研发中。
## LOAD 语法
```bash
LOAD DATA
[/*+ parallel(N) load_batch_size(M)*/]
INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_var
[, col_name_var] ...)]
[SET col_name={expr | DEFAULT},
[, col_name={expr | DEFAULT}] ...]
```
## LOAD 原理
Load Data 目前可以对 CSV 格式的文本文件进行导入,整个导入的过程大概分为以下的过程:
+ 解析文件:OB会根据用户输入的文件名,读取文件中的数据,并且根据用户的输入的并行度来决定 并行或者串行解析输入文件中的数据。
+ 分发数据:由于OB是分布式数据库系统,各个分区的数据可能分布在各个不同的observer,Load Data 会对解析出来的数据进行计算,决定数据需要被发送到哪个observer。
+ 插入数据:当目标observer 收到了发送过来的数据之后,在本地执行insert 操作把数据插入到对应的分区当中。
为了提高Load Data 语句的性能,用户可以执行加载数据的并行度,Load Data 在解析文件、计算分区、数据分发阶段都可以多个线程并行工作。 为了避免分布式事务对性能的影响,Load Data 会将按分区将数据分组,并分发到observer上进行多次写入,每次写入开启一个独立的事务,写入的数据来源于一个分组。如果在Load Data 语句执行过程中出现了错误,用户可能需要手工删除已经被加载的数据。另外,如果导入数据文件很大的话,每个节点插入数据的时间可能会很长,请根据需要调整ob_query_timeout参数。
Load Data 提供了很多选项支持用户不同的需求,目前支持的选项有:
**并行度:**
/*+ parallel(N)*/ 选项指定加载数据的并行度,默认值是N=4,建议使用的值范围是[0--租户的最大CPU数]。
```sql
load data /*+ parallel(4) */infile '/home/admin/a.csv' into table t
```
批量:
/*+ load_batch_size(M)*/ 选项指定每次插入的批量大小,默认是M=1000,根据导入数据行的总长度调整M的大小,建议使用的值是[100-1000]。
**输入文件**
INFILE 'file_name' 关键字指定输入文件的路径和文件名,目前 Load Data 只支持加载 OBSERVER 本地的输入文件。所以,用户需要在导入之前把文件拷贝到某一个observer所在机器上,并连接文件所在的observer运行Load Data 语句。
**目标表索引**
为了提高导入效率,建议先建基础表,等导入完成后,再创建表的索引。对全局索引,务必要导入之后再创建,否则可能会报not support错误。
执行权限:
用户需要授予权限才能访问机器上文件,有两步:
+ 1. 首先修改安全文件所在路径,设置为空(即无需检查) set global secure_file_priv = "";
+ 2. 对用户授予权限
+ a. mysql 模式,授予file权限:执行 grant file on *.* to USER_NAME;
**重复数据处理**
这部分指定如何处理重复的数据。Replace 表示将表中原有的数据替换成为输入文件中的数据; Ignore 表示忽略掉重复的数据。Load Data 通过表的主键来判断数据是否重复,如果表不存在主键,那么 Load Data 语句就无法判断数据是否重复,replace 和 ignore 选项没有区别。如果用户不指定这个选项,那么遇到重复数据的时候,Load Data 语句会将出现错误的数据记录到日志文件中。
**目标表选项:**
INTO TABLE tbl_name 关键字用于指定目标表名称。Load Data 支持分区表和非分区表。
**字段格式:**
这部分指定输入文件的各个字段的分隔符选项,通过 Fields|Columns 子句来指定,其中:Terminated By 关键字用来指定字段的分隔符, Enclosed By 关键字指定每个字段的开始和结束是否包含了特定的字符,Escaped By 关键字用来指定字段中的通配符。
**行格式**
这部分指定输入文件中每一行的开始和结束字符,通过 Lines 子句设置。 其中 Starting By 用于指定每一行开始的字符;Terminated By 用户指定每一行的结束字符。IGNORE number {LINES | ROWS} 子句指定忽略掉输入文件的前number行数据。
```sql
load data /*+ parallel(4) */infile '/home/admin/a.csv' into table t fields terminated by ',' lines terminated by '\n';
```
## 日志文件
如果导入的过程中出现了错误,基于 Load Data 的设计,出现错误的 insert 语句会被回滚,并且 Load Data 语句会在 OBSERVER 安装路径的 log 子目录下产生名称为 obloaddata.log.<XXXXXX> 的日志文件,以下是一个日志文件的示例:
```bash
Tenant name: mysql
File name: /home/admin/a.csv
Into table: `test`.`t`
Parallel: 1
Batch size: 1000
SQL trace: YD7A20BA65670-0005AADAAA3CAB52
Start time: 2020-07-29 21:08:13.073741
Load query:
load data infile '/home/admin/test.csv' into table t fields terminated by ',' lines terminated by '\n'
Row ErrCode ErrMsg
1 1062 Duplicated primary key
2 1062 Duplicated primary key
```
日志中会包含Load Data 产生的任务的基本信息,包含了:租户名,输入文件名,目标表名,并行度,使用的Load Data 命令。 并且以行为单位给出具体错误的信息。
## 示例
以上一节 MySQL 里导出的 CSV 为例,导入到 OceanBase 。
```bash
$ mysql -h127.1 -uroot@obmysql#obdemo -P2883 -p123456 -c -A test -Ns
MySQL [test]> select * from t1;
MySQL [test]> load data infile '/tmp/t1.csv' into table t1 fields terminated by ',' enclosed by '"' lines terminated by '\n' ;
MySQL [test]> select * from t1;
1 中 国 中 国
2 中,国 "中 国"
3 中\n国 中 \n
4 中\\"中\\国"
MySQL [test]>
```
如果有使用问题,欢迎到 OceanBase 社区版官网问答区反馈 。反馈地址:`https://open.oceanbase.com/answer/`(<https://open.oceanbase.com/answer>) 。
\ No newline at end of file
# 如何使用 DATAX 加载 CSV 数据文件到 OceanBase
## DATAX 简介
DataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS 、**OceanBase** 等各种异构数据源之间高效的数据同步功能。
开源地址:`https://github.com/alibaba/datax`
OB 企业版客户,可以跟 OceanBase 的技术人员索取 DataX 内部版本(RPM包)。 OceanBase 社区版客户,可以在 DataX 开源网站上下载源码,自行编译。
编译的时候,注意在 `pom.xml` 中剔除掉不用的数据库插件。否则,编译出来的包非常大。
## DATAX 配置文件
**DataX 迁移数据以任务的形式,每个任务只处理一个表,每个任务有一个 `json` 格式的配置文件。配置文件里会包含 `reader` 和 `writer` 两节。具体的 `reader` 和 `writer` 都是 DataX 支持的数据库插件,可以随意搭配使用(就跟孩子搭积木一样)**
最新版本的 DataX 还提供了一个 WEB 管理界面。
下面是配置文件示例。
```xml
{
"job": {
"content": [
{
"reader": {
"name": "streamreader",
"parameter": {
"sliceRecordCount": 10,
"column": [
{
"type": "long",
"value": "10"
},
{
"type": "string",
"value": "hello,你好,世界-DataX"
}
]
}
},
"writer": {
"name": "streamwriter",
"parameter": {
"encoding": "UTF-8",
"print": true
}
}
}
],
"setting": {
"speed": {
"channel": 2
}
}
}
}
```
`json` 配置文件放到 datax的目录的 `job` 下,或者自定义路径。执行方法:
```bash
$bin/datax.py job/stream2stream.json
```
输出信息:
```bash
<.....>
2021-08-26 11:06:09.217 [job-0] INFO JobContainer - PerfTrace not enable!
2021-08-26 11:06:09.218 [job-0] INFO StandAloneJobContainerCommunicator - Total 20 records, 380 bytes | Speed 38B/s, 2 records/s | Error 0 records, 0 bytes | All Task WaitWriterTime 0.000s | All Task WaitReaderTime 0.000s | Percentage 100.00%
2021-08-26 11:06:09.223 [job-0] INFO JobContainer -
任务启动时刻 : 2021-08-26 11:05:59
任务结束时刻 : 2021-08-26 11:06:09
任务总计耗时 : 10s
任务平均流量 : 38B/s
记录写入速度 : 2rec/s
读出记录总数 : 20
读写失败总数 : 0
```
DataX 任务执行结束都会有个简单的任务报告,关注一下里面 平均流量、写入速度和读写失败总数等。
DataX 的 `job` 的参数 `settings` 可以指定速度参数、错误记录容忍度等。
```xml
"setting": {
"speed": {
"channel": 10
},
"errorLimit": {
"record": 10,
"percentage": 0.1
}
}
```
**特别说明:**
+ `speed` 还有个限速的设计(`bytes`),但是有bug,大家就不要用了。 `errorLimit` 表示报错记录数的容忍度,超出这个限制后任务就中断退出。
+ `channel` 是并发数,理论上并发越大,迁移性能越好。实际也要考虑源端的读压力、网络传输性能以及目标端写入性能。
下面是常用数据源(`mysql`、`oracle` 、`csv` 和 `oceanbase` )的读写插件。
### `txtfilereader` 插件说明
`txtfilereader` 提供了读取本地文件系统数据存储的能力。在底层实现上,`txtfilereader` 获取本地文件数据,并转换为DataX传输协议传递给Writer。
本地文件内容存放的是一张逻辑意义上的二维表,例如CSV格式的文本信息。
`txtfilereader` 有一些功能限制和参数,请首先阅读官方说明: `https://github.com/alibaba/DataX/blob/master/txtfilereader/doc/txtfilereader.md` 。
下面是 `txtfilereader` 的 示例。
```xml
"reader": {
"name": "txtfilereader",
"parameter": {
"path": ["/tmp/tpcc/bmsql_oorder"],
"fileName": "bmsql_oorder",
"encoding": "UTF-8",
"column": ["*"],
"dateFormat": "yyyy-MM-dd hh:mm:ss" ,
"nullFormat": "\\N" ,
"fieldDelimiter": ","
}
}
```
**特别说明:**
+ `path` 指定到路径即可,`fileName` 会是生成的文件前缀,完整的文件名很长,有随机字符串(避免重复)。文件的数量可能是根据记录数来自动分的。
+ `column` 可以指定为 "*" ,这样所有字段值都作为字符串了。这个虽然方便,但不能保证完全没有问题。目前测试常用数据类型是可以的。
+ `nullFormat` 指定空值的记录,默认是"null",这个读入oracle的时候会有问题。建议导出文件的时候指定为 "\N" 表示空值和。
+ `fieldDelimiter` 指定 `csv` 文件的列分隔符,这个跟导出的时候指定的列分隔符保持一致。通常导出的列内容如果含有列分隔符时,会用双引号进行包含(`enclosed`)。用逗号(`,`)也可以,只是太过常见,建议用生僻一点的单字符。如 `|` 或 `^` 等。
### `mysqlreader`插件说明
MysqlReader插件实现了从Mysql读取数据。在底层实现上,MysqlReader通过JDBC连接远程Mysql数据库,并执行相应的sql语句将数据从mysql库中SELECT出来。
不同于其他关系型数据库,MysqlReader 不支持 FetchSize.
实现原理方面,简而言之,MysqlReader通过JDBC连接器连接到远程的Mysql数据库,并根据用户配置的信息生成查询SELECT SQL语句,然后发送到远程Mysql数据库,并将该SQL执行返回结果使用DataX自定义的数据类型拼装为抽象的数据集,并传递给下游Writer处理。详细功能和参数说明请首先阅读官方说明:`https://github.com/alibaba/DataX/blob/master/mysqlreader/doc/mysqlreader.md` 。
下面是 `mysqlreader` 的配置示例。
```xml
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "tpcc",
"password": "********",
"column": [
"*"
],
"connection": [
{
"table": [
"bmsql_oorder"
],
"jdbcUrl": ["jdbc:mysql://127.0.0.1:3306/tpccdb?useUnicode=true&characterEncoding=utf8"]
}
]
}
}
```
**特别说明:**
+ 如果表的主键是单列主键,比如说 `id`。那么可以在 `parameter` 下加一个配置: `"splitPk": "db_id",` 。如果是加在最后,就去掉后面的逗号(`,`)。
+ `column` 指定读取的列。通常建议写具体的列,可以在列上用函数做逻辑转换。用 `*` 就是要时刻确保列跟目标端写入的列能对应上。
### `oceanbasev10writer` 插件说明
`oceanbasev10writer` 插件实现了写入数据到 OceanBase 主库的目的表的功能。在底层实现上, OceanbaseV10Writer 通过 java客户端(底层MySQL JDBC或oceanbase client) 连接obproxy 远程 OceanBase 数据库,并执行相应的 insert sql 语句将数据写入 OceanBase ,内部会分批次提交入库。
**实现原理**
Oceanbasev10Writer 通过 DataX 框架获取 Reader 生成的协议数据,生成 insert 语句。对于mysql 租户,在主键或唯一键冲突时,可以选择 `replace` 模式,更新表中的所有字段。对于oracle 租户,目前只有 insert 行为。 出于性能考虑,写入采用 batch 方式批量写,当行数累计到预定阈值时,才发起写入请求。
下面是 `oceanbasev10writer` 的配置示例。
```xml
"writer": {
"name": "oceanbasev10writer",
"parameter": {
"obWriteMode": "insert",
"column": [
"*"
],
"preSql": [
"truncate table bmsql_oorder"
],
"connection": [
{
"jdbcUrl": "||_dsc_ob10_dsc_||obdemo:oboracle||_dsc_ob10_dsc_||jdbc:oceanbase://127.0.0.1:2883/tpcc?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true",
"table": [
"bmsql_oorder"
]
}
],
"username": "tpcc",
"password":"********",
"batchSize": 512,
"writerThreadCount":10,
"memstoreThreshold": "0.9"
}
}
```
**参数说明**
供参考,以后可能会变化,请关注`DataX` 开源地址说明 (`https://github.com/alibaba/DataX/tree/master/oceanbasev10writer`)。
+ `jdbcUrl` :
描述:目的数据库的连接信息,包含了ob的集群、租户、obproxy的地址和端口以及库名;使用域名可能会报错,建议使用 `ip` 。
必选:是
默认值:无
+ `table`:
描述:目的表的表名称。支持写入一个或者多个表。当配置为多张表时,必须确保所有表结构保持一致;表名中一般不含库名;
必选:是
默认值:无
+ `column`:
描述:目的表需要写入数据的字段,字段之间用英文逗号分隔。例如: "column": ["id","name","age"]。
**column配置项必须指定,不能留空!**
必选:是
默认值:否
+ `preSql`:
描述:写入数据到目的表前,会先执行这里的标准语句。如果 Sql 中有你需要操作到的表名称,请使用 @table 表示,这样在实际执行 Sql 语句时,会对变量按照实际表名称进行替换。比如你的任务是要写入到目的端的100个同构分表(表名称为:datax_00,datax01, ... datax_98,datax_99),并且你希望导入数据前,先对表中数据进行删除操作,那么你可以这样配置:"preSql":["delete from @table"],效果是:在执行到每个表写入数据前,会先执行对应的 delete from 对应表名称.只支持delete语句
必选:否
默认值:无
+ `batchSize`:
描述:一次性批量提交的记录数大小,该值可以极大减少DataX与Oceanbase的网络交互次数,并提升整体吞吐量。但是该值设置过大可能会造成DataX运行进程OOM情况。
必选:否
默认值:1000
+ `memstoreThreshold`:
描述:OB租户的memstore使用率,当达到这个阀值的时候暂停导入,等释放内存后继续导入. 防止租户内存溢出。
必选:否
默认值:0.9
+ `username`:
描述:访问oceanbase1.0的用户名,注意,此处不配置ob的集群名和租户名。
必选:是
默认值:无
+ `** password**`
描述:访问oceanbase1.0的密码
必选:是
默认值:无
+ `writerThreadCount`:
描述:每个通道(channel)中写入使用的线程数
必选:否
默认值:1
## MySQL 数据导出到 CSV 文件
先将 MySQL 数据导出到 CSV 文件。
配置文件如下:
```xml
$cat job/bmsql_oorder_mysql2csv.json
{
"job": {
"setting": {
"speed": {
"channel": 4
},
"errorLimit": {
"record": 0,
"percentage": 0.1
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "tpcc",
"password": "********",
"column": [
"*"
],
"connection": [
{
"table": [
"bmsql_oorder"
],
"jdbcUrl": ["jdbc:mysql://127.0.0.1:3306/tpccdb?useUnicode=true&characterEncoding=utf8"]
}
]
}
},
"writer": {
"name": "txtfilewriter",
"parameter": {
"path": "/tmp/tpcc/bmsql_oorder",
"fileName": "bmsql_oorder",
"encoding": "UTF-8",
"writeMode": "truncate",
"dateFormat": "yyyy-MM-dd hh:mm:ss" ,
"nullFormat": "\\N" ,
"fileFormat": "csv" ,
"fieldDelimiter": ","
}
}
}
]
}
}
```
## CSV 文件导入到 OB
将源端导出的 CSV 文件复制到目标端的 DATAX 服务器上,然后导入到目标端 OceanBase 中。
配置文件如下:
```xml
$cat job/bmsql_oorder_csv2ob.json
{
"job": {
"setting": {
"speed": {
"channel": 4
},
"errorLimit": {
"record": 0,
"percentage": 0.1
}
},
"content": [
{
"reader": {
"name": "txtfilereader",
"parameter": {
"path": ["/tmp/tpcc/bmsql_oorder"],
"fileName": "bmsql_oorder",
"encoding": "UTF-8",
"column": ["*"],
"dateFormat": "yyyy-MM-dd hh:mm:ss" ,
"nullFormat": "\\N" ,
"fieldDelimiter": ","
}
},
"writer": {
"name": "oceanbasev10writer",
"parameter": {
"obWriteMode": "insert",
"column": [
"*"
],
"preSql": [
"truncate table bmsql_oorder"
],
"connection": [
{
"jdbcUrl": "||_dsc_ob10_dsc_||obdemo:oboracle||_dsc_ob10_dsc_||jdbc:oceanbase://127.0.0.1:2883/tpcc?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true",
"table": [
"bmsql_oorder"
]
}
],
"username": "tpcc",
"password":"********",
"writerThreadCount":10,
"batchSize": 1000,
"memstoreThreshold": "0.9"
}
}
}
]
}
}
```
# 如何使用 DATAX 迁移 MySQL数据到 OceanBase
将 MySQL 数据迁移到 OceanBase ,如果源端和目标端不能同时跟 DATAX 服务器网络联通,则使用上面方法通过 CSV 文件中转。如果源端数据库和目标端数据库能同时跟 DATAX 所在服务器联通,则可以使用 DATAX 直接将数据从源端迁移到目标端。
## MySQL 数据同步到 OceanBase
配置文件如下:
```xml
{
"job": {
"setting": {
"speed": {
"channel": 4
},
"errorLimit": {
"record": 0,
"percentage": 0.1
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "tpcc",
"password": "********",
"column": [
"*"
],
"connection": [
{
"table": [
"bmsql_oorder"
],
"jdbcUrl": ["jdbc:mysql://127.0.0.1:3306/tpccdb?useUnicode=true&characterEncoding=utf8"]
}
]
}
},
"writer": {
"name": "oceanbasev10writer",
"parameter": {
"obWriteMode": "insert",
"column": [
"*"
],
"preSql": [
"truncate table bmsql_oorder"
],
"connection": [
{
"jdbcUrl": "||_dsc_ob10_dsc_||obdemo:oboracle||_dsc_ob10_dsc_||jdbc:oceanbase://127.0.0.1:2883/tpcc?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true",
"table": [
"bmsql_oorder"
]
}
],
"username": "tpcc",
"password":"********",
"writerThreadCount":10,
"batchSize": 1000,
"memstoreThreshold": "0.9"
}
}
}
]
}
}
```
# 如何使用 DATAX 迁移 OceanBase 数据到 MySQL/ORACLE
## OceanBase 数据同步到 MySQL
使用 OceanBase Reader 和 MySQL 的 Writer 搭配实现 OceanBase 数据同步到 MySQL 。
配置文件如下:
```xml
{
"job": {
"setting": {
"speed": {
"channel": 16
},
"errorLimit": {
"record": 0,
"percentage": 0.1
}
},
"content": [
{
"reader": {
"name": "oceanbasev10reader",
"parameter": {
"where": "",
"readBatchSize": 10000,
"column": [
"*"
],
"connection": [
{
"jdbcUrl": ["||_dsc_ob10_dsc_||obdemo:oboracle||_dsc_ob10_dsc_||jdbc:oceanbase://127.0.0.1:2883/tpcc"],
"table": [
"bmsql_oorder"
]
}
],
"username": "tpcc",
"password":"********"
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"writeMode": "replace",
"username": "tpcc",
"password": "123456",
"column": [
"*"
],
"session": [
"set session sql_mode='ANSI'"
],
"preSql": [
"truncate table bmsql_oorder"
],
"batchSize": 512,
"connection": [
{
"jdbcUrl": "jdbc:mysql://127.0.0.1:3306/tpccdb?useUnicode=true&characterEncoding=utf8",
"table": [
"bmsql_oorder"
]
}
]
}
}
}
]
}
}
```
## OceanBase 数据同步到 ORACLE
配置文件如下:
```xml
{
"job": {
"setting": {
"speed": {
"channel": 16
},
"errorLimit": {
"record": 0,
"percentage": 0.1
}
},
"content": [
{
"reader": {
"name": "oceanbasev10reader",
"parameter": {
"where": "",
"readBatchSize": 10000,
"column": [
"*"
],
"connection": [
{
"jdbcUrl": ["||_dsc_ob10_dsc_||obdemo:oboracle||_dsc_ob10_dsc_||jdbc:oceanbase://127.0.0.1:2883/tpcc"],
"table": [
"bmsql_oorder"
]
}
],
"username": "tpcc",
"password":"********"
}
},
"writer": {
"name": "oraclewriter",
"parameter": {
"username": "tpcc",
"password": "********",
"column": [
"*"
],
"preSql": [
"truncate table bmsql_oorder"
],
"batchSize": 512,
"connection": [
{
"jdbcUrl": "jdbc:oracle:thin:@127.0.0.1:1521:helowin",
"table": [
"bmsql_oorder"
]
}
]
}
}
}
]
}
}
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册