DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、DRDS 等各种异构数据源之间高效的数据同步功能。
Github地址:https://github.com/alibaba/DataX
DataX 是一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。
设计理念
为了解决异构数据源同步问题,DataX将复杂的网状的同步链路变成了星型数据链路,DataX作为中间传输载体负责连接各种数据源。当需要接入一个新的数据源的时候,只需要将此数据源对接到DataX,便能跟已有的数据源做到无缝数据同步。
当前使用现状
DataX在阿里巴巴集团内被广泛使用,承担了所有大数据的离线同步业务,并已持续稳定运行了6年之久。目前每天完成同步8w多道作业,每日传输数据量超过300TB。
此前已经开源DataX1.0版本,此次介绍为阿里云开源全新版本DataX3.0,有了更多更强大的功能和更好的使用体验。Github主页地址:https://github.com/alibaba/DataX
DataX本身作为数据同步框架,将不同数据源的同步抽象为从源头数据源读取数据的Reader插件,以及向目标端写入数据的Writer插件,理论上DataX框架可以支持任意数据源类型的数据同步工作。同时DataX插件体系作为一套生态系统, 每接入一套新数据源该新加入的数据源即可实现和现有的数据源互通。
地址:https://github.com/alibaba/DataX/blob/master/introduction.md
DataX本身作为离线数据同步框架,采用Freamwork + plugin架构构建。将数据源读取和写入抽象成为Reader/Writer插件,纳入到整个同步框架中。
Reader: Reader�为数据采集模块,负责采集数据源的数据,将数据发送给Framework。
Writer: Writer为数据写入模块,负责不断向Framework取数据,并将数据写入到目的端。
Framework: Framework用于连接reader和writer,作为两者的数据传输通道,并处理缓冲,流控,并发,数据转换等核心技术问题。
DataX目前已经有了比较全面的插件体系,主流的RDBMS数据库、NOSQL、大数据计算系统都已经接入,目前支持数据如下图,详情请点击:(https://github.com/alibaba/DataX/blob/master/introduction.md)
DataX3.0开源版本支持单机多线程模式完成同步作业运行,本小节按一个DataX作业声明周期的时序图,从整体架构设计非常简要说明DataX各个模块相互关系。
核心模块介绍:
1.DataX完成单个数据同步的作业,我们称之为Job,DataX接受一个Job之后,将启动一个进程来完成整个作业同步过程。DataX Job模块是单个作业的中枢管理节点,承担了数据清洗、子任务切分(将单一作业计算转化为多个子Task).
2.DataXJob启动后,会根据不同的源端切分策略,将job切分成多个小的Task(子任务),以便于并发执行。Task便是DataX作业的最小单元,每一个Task都负责一部分数据的同步工作。
3.切分多个Task之后,DataX Job会调用Scheduler模块儿,根据配置的并发数据量,将拆分成的Task重新组合,组装成TaskGroup(任务组)。每一个TaskGroup负责以一定的并发运行完毕分配好的所有Task,默认单个任务组的并发数量为5.
4:每一个Task都由TaskGroup负责启动,Task启动后,会固定启动ReaderChannelWriter的线程来完成任务同步工作。
5.DataX作业运行起来之后,Job监控并等待多个TaskGroup模块任务完成,等待所有TaskGroup任务完成后Job成功退出。否则,异常退出,进程退出值非0.
DataX调度流程:
举例来说,用户提交了一个DataX作业,并配置了20个并发,目的是将一个100张分表的mysql数据同步到odps里面。
DataX的调度决策思路是:
1.DataXJob根据分库分表切分成了100个Task.
2.根据20个并发,DataX计算共需要分配4个TaskGroup. (默认每个TaskGroup的并发数量是5)
3.4个TaskGrou平均切分好的100个Task,每一个TaskGroup负责5个并发共计25个Task.
可靠的数据质量监控
完美解决数据传输个别类型失真问题
DataX旧版对于部分数据类型(比如时间戳)传输一直存在毫秒阶段等数据失真情况,新版本DataX3.0已经做到支持所有的强数据类型,每一种插件都有自己的数据类型转换策略,让数据可以完整无损的传输到目的端。
提供作业全链路的流量、数据量运行时监控
DataX3.0运行过程中可以将作业本身状态、数据流量、数据速度、执行进度等信息进行全面的展示,让用户可以实时了解作业状态。并可在作业执行过程中智能判断源端和目的端的速度对比情况,给予用户更多性能排查信息。
提供脏数据探测
在大量数据的传输过程中,必定会由于各种原因导致很多数据传输报错(比如类型转换错误),这种数据DataX认为就是脏数据。DataX目前可以实现脏数据精确过滤、识别、采集、展示,为用户提供多种的脏数据处理模式,让用户准确把控数据质量大关!
丰富的数据转换功能
DataX作为一个服务于大数据的ETL工具,除了提供数据快照搬迁功能之外,还提供了丰富数据转换的功能,让数据在传输过程中可以轻松完成数据脱敏,补全,过滤等数据转换功能,另外还提供了自动groovy函数,让用户自定义转换函数。详情请看DataX3的transformer详细介绍。
精准的速度控制
还在为同步过程中对线程存储压力影响而担心吗?新版本DataX3.0提供了包括通道(并发)、记录流、字节流三种流控模式,可以随意控制你的作业速度,让你的作业在库可以在承受的范围内达到最佳的同步速度。
"speed": {
"channel": 5,
"byte": 1048576,
"record": 10000
}
强劲的同步性能
DataX3.0每一种读插件都有一种或多种切分策略,都能将作业合理切分成多个Task并行执行,单机多线程执行模型可以让DataX速度随并发成线性增长。在源端和目的端性能都足够的情况下,单个作业一定可以打满网卡。另外,DataX团队对所有的已经接入的插件都做了极致的性能优化,并且做了完整的性能测试。性能测试相关详情可以参照每单个数据源的详细介绍:https://github.com/alibaba/DataX/wiki/DataX-all-data-channels
健壮的容错机制
DataX作业是极易受外部因素的干扰,网络闪断、数据源不稳定等因素很容易让同步到一半的作业报错停止。因此稳定性是DataX的基本要求,在DataX 3.0的设计中,重点完善了框架和插件的稳定性。目前DataX3.0可以做到线程级别、进程级别(暂时未开放)、作业级别多层次局部/全局的重试,保证用户的作业稳定运行。
• 线程内部重试
DataX的核心插件都经过团队的全盘review,不同的网络交互方式都有不同的重试策略。
• 线程级别重试
目前DataX已经可以实现TaskFailover,针对于中间失败的Task,DataX框架可以做到整个Task级别的重新调度。
极简的使用体验
• 易用
下载即可用,支持linux和windows,只需要短短几步骤就可以完成数据的传输。
• 详细
DataX在运行日志中打印了大量信息,其中包括传输速度,Reader、Writer性能,进程CPU,JVM和GC情况等等。
传输过程中打印传输速度、精度等
传输过程中打印进程相关的CPU、JVM等
下载地址:http://datax-opensource.oss-cn-hangzhou.aliyuncs.com/datax.tar.gz
Quick start地址:https://github.com/alibaba/DataX/blob/master/userGuid.md
• Linux
• JDK(1.8以上,推荐1.8)
• Python(推荐Python2.6.X)
• Apache Maven 3.x (Compile DataX)
方法一、直接下载DataX工具包:DataX下载地址(http://datax-opensource.oss-cn-hangzhou.aliyuncs.com/datax.tar.gz)
下载后解压至本地某个目录,进入bin目录,即可运行同步作业:
$ cd {YOUR_DATAX_HOME}/bin
$ python datax.py {YOUR_JOB.json}
自检脚本:python {YOUR_DATAX_HOME}/bin/datax.py {YOUR_DATAX_HOME}/job/job.json
方法二:下载DataX源码,自己编译:https://github.com/alibaba/DataX
(1)、下载DataX源码:
$ git clone [email protected]:alibaba/DataX.git
(2)、通过maven打包
$ cd {DataX_source_code_home}
$ mvn -U clean package assembly:assembly -Dmaven.test.skip=true
打包成功,日志显示如下:
[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------------
[INFO] Total time: 08:12 min
[INFO] Finished at: 2015-12-13T16:26:48+08:00
[INFO] Final Memory: 133M/960M
[INFO] -----------------------------------------------------------------
打包成功后的DataX包位于{DataX_source_code_home}/target/datax/datax/,结构如下:
$ cd {DataX_source_code_home}
$ ls ./target/datax/datax/
bin conf job lib log log_perf plugin script tmp
(1)、第一步、创建创业的的配置文件(json格式)
可以通过命令查看配置模板:python datax.py -r {YOUR_READER} -w {YOUR_WRITER}
[root@hadoop1 bin]# pwd
/home/installed/datax/bin
[root@hadoop1 bin]# python datax.py -r streamreader -w streamwriter
DataX (DATAX-OPENSOURCE-3.0), From Alibaba !
Copyright (C) 2010-2017, Alibaba Group. All Rights Reserved.
Please refer to the streamreader document:
https://github.com/alibaba/DataX/blob/master/streamreader/doc/streamreader.md
Please refer to the streamwriter document:
https://github.com/alibaba/DataX/blob/master/streamwriter/doc/streamwriter.md
Please save the following configuration as a json file and use
python {DATAX_HOME}/bin/datax.py {JSON_FILE_NAME}.json
to run the job.
{
"job": {
"content": [
{
"reader": {
"name": "streamreader",
"parameter": {
"column": [],
"sliceRecordCount": ""
}
},
"writer": {
"name": "streamwriter",
"parameter": {
"encoding": "",
"print": true
}
}
}
],
"setting": {
"speed": {
"channel": ""
}
}
}
}
[root@hadoop1 bin]#
根据模板配置json如下:
#stream2stream.json
{
"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": 5
}
}
}
}
第二步:启动DataX
[root@hadoop3 datax]# cd /home/installed/datax/bin/
[root@hadoop3 bin]# python datax.py /home/test/dataxtest/stream2stream.json
DataX (DATAX-OPENSOURCE-3.0), From Alibaba !
Copyright (C) 2010-2017, Alibaba Group. All Rights Reserved.
2019-09-09 16:14:17.345 [main] INFO VMInfo - VMInfo# operatingSystem class => sun.management.OperatingSystemImpl
2019-09-09 16:14:17.356 [main] INFO Engine - the machine info =>
osInfo: Oracle Corporation 1.8 25.161-b12
jvmInfo: Linux amd64 3.10.0-693.el7.x86_64
cpu num: 4
totalPhysicalMemory: -0.00G
freePhysicalMemory: -0.00G
maxFileDescriptorCount: -1
currentOpenFileDescriptorCount: -1
GC Names [PS MarkSweep, PS Scavenge]
MEMORY_NAME | allocation_size | init_size
PS Eden Space | 256.00MB | 256.00MB
Code Cache | 240.00MB | 2.44MB
Compressed Class Space | 1,024.00MB | 0.00MB
PS Survivor Space | 42.50MB | 42.50MB
PS Old Gen | 683.00MB | 683.00MB
Metaspace | -0.00MB | 0.00MB
2019-09-09 16:14:17.375 [main] INFO Engine -
{
"content":[
{
"reader":{
"name":"streamreader",
"parameter":{
"column":[
{
"type":"long",
"value":"10"
},
{
"type":"string",
"value":"hello,你好,世界-DataX"
}
],
"sliceRecordCount":10
}
},
"writer":{
"name":"streamwriter",
"parameter":{
"encoding":"UTF-8",
"print":true
}
}
}
],
"setting":{
"speed":{
"channel":5
}
}
}
2019-09-09 16:14:17.404 [main] WARN Engine - prioriy set to 0, because NumberFormatException, the value is: null
2019-09-09 16:14:17.406 [main] INFO PerfTrace - PerfTrace traceId=job_-1, isEnable=false, priority=0
2019-09-09 16:14:17.406 [main] INFO JobContainer - DataX jobContainer starts job.
2019-09-09 16:14:17.409 [main] INFO JobContainer - Set jobId = 0
2019-09-09 16:14:17.431 [job-0] INFO JobContainer - jobContainer starts to do prepare ...
2019-09-09 16:14:17.432 [job-0] INFO JobContainer - DataX Reader.Job [streamreader] do prepare work .
2019-09-09 16:14:17.432 [job-0] INFO JobContainer - DataX Writer.Job [streamwriter] do prepare work .
2019-09-09 16:14:17.433 [job-0] INFO JobContainer - jobContainer starts to do split ...
2019-09-09 16:14:17.433 [job-0] INFO JobContainer - Job set Channel-Number to 5 channels.
2019-09-09 16:14:17.434 [job-0] INFO JobContainer - DataX Reader.Job [streamreader] splits to [5] tasks.
2019-09-09 16:14:17.435 [job-0] INFO JobContainer - DataX Writer.Job [streamwriter] splits to [5] tasks.
2019-09-09 16:14:17.467 [job-0] INFO JobContainer - jobContainer starts to do schedule ...
2019-09-09 16:14:17.485 [job-0] INFO JobContainer - Scheduler starts [1] taskGroups.
2019-09-09 16:14:17.488 [job-0] INFO JobContainer - Running by standalone Mode.
2019-09-09 16:14:17.507 [taskGroup-0] INFO TaskGroupContainer - taskGroupId=[0] start [5] channels for [5] tasks.
2019-09-09 16:14:17.513 [taskGroup-0] INFO Channel - Channel set byte_speed_limit to -1, No bps activated.
2019-09-09 16:14:17.513 [taskGroup-0] INFO Channel - Channel set record_speed_limit to -1, No tps activated.
2019-09-09 16:14:17.545 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[2] attemptCount[1] is started
2019-09-09 16:14:17.558 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[3] attemptCount[1] is started
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
2019-09-09 16:14:17.580 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[1] attemptCount[1] is started
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
2019-09-09 16:14:17.598 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[4] attemptCount[1] is started
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
2019-09-09 16:14:17.619 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[0] attemptCount[1] is started
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
10 hello,你好,世界-DataX
2019-09-09 16:14:17.731 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[0] is successed, used[112]ms
2019-09-09 16:14:17.731 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[1] is successed, used[163]ms
2019-09-09 16:14:17.731 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[2] is successed, used[202]ms
2019-09-09 16:14:17.731 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[3] is successed, used[177]ms
2019-09-09 16:14:17.732 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] taskId[4] is successed, used[136]ms
2019-09-09 16:14:17.733 [taskGroup-0] INFO TaskGroupContainer - taskGroup[0] completed it's tasks.
2019-09-09 16:14:27.511 [job-0] INFO StandAloneJobContainerCommunicator - Total 50 records, 950 bytes | Speed 95B/s, 5 records/s | Error 0 records, 0 bytes | All Task WaitWriterTime 0.000s | All Task WaitReaderTime 0.000s | Percentage 100.00%
2019-09-09 16:14:27.511 [job-0] INFO AbstractScheduler - Scheduler accomplished all tasks.
2019-09-09 16:14:27.511 [job-0] INFO JobContainer - DataX Writer.Job [streamwriter] do post work.
2019-09-09 16:14:27.512 [job-0] INFO JobContainer - DataX Reader.Job [streamreader] do post work.
2019-09-09 16:14:27.512 [job-0] INFO JobContainer - DataX jobId [0] completed successfully.
2019-09-09 16:14:27.513 [job-0] INFO HookInvoker - No hook invoked, because base dir not exists or is a file: /home/installed/datax/hook
2019-09-09 16:14:27.515 [job-0] INFO JobContainer -
[total cpu info] =>
averageCpu | maxDeltaCpu | minDeltaCpu
-1.00% | -1.00% | -1.00%
[total gc info] =>
NAME | totalGCCount | maxDeltaGCCount | minDeltaGCCount | totalGCTime | maxDeltaGCTime | minDeltaGCTime
PS MarkSweep | 0 | 0 | 0 | 0.000s | 0.000s | 0.000s
PS Scavenge | 0 | 0 | 0 | 0.000s | 0.000s | 0.000s
2019-09-09 16:14:27.516 [job-0] INFO JobContainer - PerfTrace not enable!
2019-09-09 16:14:27.516 [job-0] INFO StandAloneJobContainerCommunicator - Total 50 records, 950 bytes | Speed 95B/s, 5 records/s | Error 0 records, 0 bytes | All Task WaitWriterTime 0.000s | All Task WaitReaderTime 0.000s | Percentage 100.00%
2019-09-09 16:14:27.517 [job-0] INFO JobContainer -
任务启动时刻 : 2019-09-09 16:14:17
任务结束时刻 : 2019-09-09 16:14:27
任务总计耗时 : 10s
任务平均流量 : 95B/s
记录写入速度 : 5rec/s
读出记录总数 : 50
读写失败总数 : 0
[root@hadoop3 bin]#
MysqlReader插件实现了从Mysql读取数据。在底层实现上,MysqlReader通过JDBC连接远程Mysql数据库,并执行相应的sql语句将数据从mysql库中SELECT出来。
不同于其他关系型数据库,MysqlReader不支持FetchSize.
简而言之,MysqlReader通过JDBC连接器连接到远程的Mysql数据库,并根据用户配置的信息生成查询SELECT SQL语句,然后发送到远程Mysql数据库,并将该SQL执行返回结果使用DataX自定义的数据类型拼装为抽象的数据集,并传递给下游Writer处理。
对于用户配置Table、Column、Where的信息,MysqlReader将其拼接为SQL语句发送到Mysql数据库;对于用户配置querySql信息,MysqlReader直接将其发送到Mysql数据库。
• 配置一个从Mysql数据库同步抽取数据到本地的作业:
{
"job": {
"setting": {
"speed": {
"channel": 3
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "root",
"column": [
"id",
"name"
],
"splitPk": "db_id",
"connection": [
{
"table": [
"table"
],
"jdbcUrl": [
"jdbc:mysql://127.0.0.1:3306/database"
]
}
]
}
},
"writer": {
"name": "streamwriter",
"parameter": {
"print":true
}
}
}
]
}
}
• 配置一个自定义SQL的数据库同步任务到本地内容的作业:
{
"job": {
"setting": {
"speed": {
"channel":1
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "root",
"connection": [
{
"querySql": [
"select db_id,on_line_flag from db_info where db_id < 10;"
],
"jdbcUrl": [
"jdbc:mysql://bad_ip:3306/database",
"jdbc:mysql://127.0.0.1:bad_port/database",
"jdbc:mysql://127.0.0.1:3306/database"
]
}
]
}
},
"writer": {
"name": "streamwriter",
"parameter": {
"print": false,
"encoding": "UTF-8"
}
}
}
]
}
}
• jdbcUrl
描述:描述的是到对端数据库的JDBC连接信息,使用JSON的数组描述,并支持一个库填写多个连接地址。之所以使用JSON数组描述连接信息,是因为阿里集团内部支持多个IP探测,如果配置了多个,MysqlReader可以依次探测ip的可连接性,直到选择一个合法的IP。
如果全部连接失败,MysqlReader报错。 注意,jdbcUrl必须包含在connection配置单元中。对于阿里集团外部使用情况,JSON数组填写一个JDBC连接即可。
jdbcUrl按照Mysql官方规范,并可以填写连接附件控制信息。具体请参看Mysql官方文档。
必选:是
默认值:无
• username
描述:数据源的用户名
必选:是
默认值:无
• password
描述:数据源指定用户名的密码
必选:是
默认值:无
• table
描述:所选取的需要同步的表。使用JSON的数组描述,因此支持多张表同时抽取。当配置为多张表时,用户自己需保证多张表是同一schema结构,MysqlReader不予检查表是否同一逻辑表。注意,table必须包含在connection配置单元中。
必选:是
默认值:无
• column
描述:所配置的表中需要同步的列名集合,使用JSON的数组描述字段信息。用户使用代表默认使用所有列配置,例如[’’]。
支持列裁剪,即列可以挑选部分列进行导出。
支持列换序,即列可以不按照表schema信息进行导出。
支持常量配置,用户需要按照Mysql SQL语法格式: [“id”, “table
”, “1”, “‘bazhen.csy’”, “null”, “to_char(a + 1)”, “2.3” , “true”] id为普通列名,table
为包含保留在的列名,1为整形数字常量,'bazhen.csy’为字符串常量,null为空指针,to_char(a + 1)为表达式,2.3为浮点数,true为布尔值。
必选:是
默认值:无
• splitPk
描述:MysqlReader进行数据抽取时,如果指定splitPk,表示用户希望使用splitPk代表的字段进行数据分片,DataX因此会启动并发任务进行数据同步,这样可以大大提供数据同步的效能。
推荐splitPk用户使用表主键,因为表主键通常情况下比较均匀,因此切分出来的分片也不容易出现数据热点。
目前splitPk仅支持整形数据切分,不支持浮点、字符串、日期等其他类型。如果用户指定其他非支持类型,MysqlReader将报错!
如果splitPk不填写,包括不提供splitPk或者splitPk值为空,DataX视作使用单通道同步该表数据。
必选:否
默认值:空
• where
描述:筛选条件,MysqlReader根据指定的column、table、where条件拼接SQL,并根据这个SQL进行数据抽取。在实际业务场景中,往往会选择当天的数据进行同步,可以将where条件指定为gmt_create > $bizdate 。注意:不可以将where条件指定为limit 10,limit不是SQL的合法where子句。
where条件可以有效地进行业务增量同步。如果不填写where语句,包括不提供where的key或者value,DataX均视作同步全量数据。
必选:否
默认值:无
• querySql
描述:在有些业务场景下,where这一配置项不足以描述所筛选的条件,用户可以通过该配置型来自定义筛选SQL。当用户配置了这一项之后,DataX系统就会忽略table,column这些配置型,直接使用这个配置项的内容对数据进行筛选,例如需要进行多表join后同步数据,使用select a,b from table_a join table_b on table_a.id = table_b.id
当用户配置querySql时,MysqlReader直接忽略table、column、where条件的配置,querySql优先级大于table、column、where选项。
必选:否
默认值:无
目前MysqlReader支持大部分Mysql类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。
下面列出MysqlReader针对Mysql类型转换列表:
请注意:
除上述罗列字段类型外,其他类型均不支持。
tinyint(1) DataX视作为整形。
year DataX视作为字符串类型
bit DataX属于未定义行为。
1 主备同步数据恢复问题
主备同步问题指Mysql使用主从灾备,备库从主库不间断通过binlog恢复数据。由于主备数据同步存在一定的时间差,特别在于某些特定情况,例如网络延迟等问题,导致备库同步恢复的数据与主库有较大差别,导致从备库同步的数据不是一份当前时间的完整镜像。
针对这个问题,我们提供了preSql功能,该功能待补充。
2 一致性约束
Mysql在数据存储划分中属于RDBMS系统,对外可以提供强一致性数据查询接口。例如当一次同步任务启动运行过程中,当该库存在其他数据写入方写入数据时,MysqlReader完全不会获取到写入更新数据,这是由于数据库本身的快照特性决定的。关于数据库快照特性,请参看MVCC Wikipedia
上述是在MysqlReader单线程模型下数据同步一致性的特性,由于MysqlReader可以根据用户配置信息使用了并发数据抽取,因此不能严格保证数据一致性:当MysqlReader根据splitPk进行数据切分后,会先后启动多个并发任务完成数据同步。由于多个并发任务相互之间不属于同一个读事务,同时多个并发任务存在时间间隔。因此这份数据并不是完整的、一致的数据快照信息。
针对多线程的一致性快照需求,在技术上目前无法实现,只能从工程角度解决,工程化的方式存在取舍,我们提供几个解决思路给用户,用户可以自行选择:
使用单线程同步,即不再进行数据切片。缺点是速度比较慢,但是能够很好保证一致性。
关闭其他数据写入方,保证当前数据为静态数据,例如,锁表、关闭备库同步等等。缺点是可能影响在线业务。
3 数据库编码问题
Mysql本身的编码设置非常灵活,包括指定编码到库、表、字段级别,甚至可以均不同编码。优先级从高到低为字段、表、库、实例。我们不推荐数据库用户设置如此混乱的编码,最好在库级别就统一到UTF-8。
MysqlReader底层使用JDBC进行数据抽取,JDBC天然适配各类编码,并在底层进行了编码转换。因此MysqlReader不需用户指定编码,可以自动获取编码并转码。
对于Mysql底层写入编码和其设定的编码不一致的混乱情况,MysqlReader对此无法识别,对此也无法提供解决方案,对于这类情况,导出有可能为乱码。
4 增量数据同步
MysqlReader使用JDBC SELECT语句完成数据抽取工作,因此可以使用SELECT…WHERE…进行增量数据抽取,方式有多种:
数据库在线应用写入数据库时,填充modify字段为更改时间戳,包括新增、更新、删除(逻辑删)。对于这类应用,MysqlReader只需要WHERE条件跟上一同步阶段时间戳即可。
对于新增流水型数据,MysqlReader可以WHERE条件后跟上一阶段最大自增ID即可。
对于业务上无字段区分新增、修改数据情况,MysqlReader也无法进行增量数据同步,只能同步全量数据。
5 Sql安全性
MysqlReader提供querySql语句交给用户自己实现SELECT抽取语句,MysqlReader本身对querySql不做任何安全性校验。这块交由DataX用户方自己保证。
FAQ
Q: MysqlReader同步报错,报错信息为XXX
A: 网络或者权限问题,请使用mysql命令行测试:
mysql -u -p -h -D -e "select * from <表名>"
如果上述命令也报错,那可以证实是环境问题,请联系你的DBA。
1 快速介绍
MysqlWriter 插件实现了写入数据到 Mysql 主库的目的表的功能。在底层实现上, MysqlWriter 通过 JDBC 连接远程 Mysql 数据库,并执行相应的 insert into … 或者 ( replace into …) 的 sql 语句将数据写入 Mysql,内部会分批次提交入库,需要数据库本身采用 innodb 引擎。
MysqlWriter 面向ETL开发工程师,他们使用 MysqlWriter 从数仓导入数据到 Mysql。同时 MysqlWriter 亦可以作为数据迁移工具为DBA等用户提供服务。
2 实现原理
MysqlWriter 通过 DataX 框架获取 Reader 生成的协议数据,根据你配置的 writeMode 生成
• insert into…(当主键/唯一性索引冲突时会写不进去冲突的行)
或者
• replace into…(没有遇到主键/唯一性索引冲突时,与 insert into 行为一致,冲突时会用新行替换原有行所有字段) 的语句写入数据到 Mysql。出于性能考虑,采用了 PreparedStatement + Batch,并且设置了:rewriteBatchedStatements=true,将数据缓冲到线程上下文 Buffer 中,当 Buffer 累计到预定阈值时,才发起写入请求。
注意:目的表所在数据库必须是主库才能写入数据;整个任务至少需要具备 insert/replace into…的权限,是否需要其他权限,取决于你任务配置中在 preSql 和 postSql 中指定的语句。
• 这里使用一份从内存产生到 Mysql 导入的数据。
{
"job": {
"setting": {
"speed": {
"channel": 1
}
},
"content": [
{
"reader": {
"name": "streamreader",
"parameter": {
"column" : [
{
"value": "DataX",
"type": "string"
},
{
"value": 19880808,
"type": "long"
},
{
"value": "1988-08-08 08:08:08",
"type": "date"
},
{
"value": true,
"type": "bool"
},
{
"value": "test",
"type": "bytes"
}
],
"sliceRecordCount": 1000
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"writeMode": "insert",
"username": "root",
"password": "root",
"column": [
"id",
"name"
],
"session": [
"set session sql_mode='ANSI'"
],
"preSql": [
"delete from test"
],
"connection": [
{
"jdbcUrl": "jdbc:mysql://127.0.0.1:3306/datax?useUnicode=true&characterEncoding=gbk",
"table": [
"test"
]
}
]
}
}
}
]
}
}
• jdbcUrl
o 描述:目的数据库的 JDBC 连接信息。作业运行时,DataX 会在你提供的 jdbcUrl 后面追加如下属性:yearIsDateType=false&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true
o 注意:1、在一个数据库上只能配置一个 jdbcUrl 值。这与 MysqlReader 支持多个备库探测不同,因为此处不支持同一个数据库存在多个主库的情况(双主导入数据情况)
o 2、jdbcUrl按照Mysql官方规范,并可以填写连接附加控制信息,比如想指定连接编码为 gbk ,则在 jdbcUrl 后面追加属性 useUnicode=true&characterEncoding=gbk。具体请参看 Mysql官方文档或者咨询对应 DBA。
o 必选:是
o 默认值:无
• username
o 描述:目的数据库的用户名
o 必选:是
o 默认值:无
• password
o 描述:目的数据库的密码
o 必选:是
o 默认值:无
• table
o 描述:目的表的表名称。支持写入一个或者多个表。当配置为多张表时,必须确保所有表结构保持一致。
o 注意:table 和 jdbcUrl 必须包含在 connection 配置单元中
o 必选:是
o 默认值:无
• column
o 描述:目的表需要写入数据的字段,字段之间用英文逗号分隔。例如: "column": ["id","name","age"]。如果要依次写入全部列,使用表示, 例如: "column": [""]。
o **column配置项必须指定,不能留空!**
o
o 注意:1、我们强烈不推荐你这样配置,因为当你目的表字段个数、类型等有改动时,你的任务可能运行不正确或者失败
o 2、 column 不能配置任何常量值
o 必选:是
o 默认值:否
• session
o 描述: DataX在获取Mysql连接时,执行session指定的SQL语句,修改当前connection session属性
o 必须: 否
o 默认值: 空
• preSql
o 描述:写入数据到目的表前,会先执行这里的标准语句。如果 Sql 中有你需要操作到的表名称,请使用 @table 表示,这样在实际执行 Sql 语句时,会对变量按照实际表名称进行替换。比如你的任务是要写入到目的端的100个同构分表(表名称为:datax_00,datax01, ... datax_98,datax_99),并且你希望导入数据前,先对表中数据进行删除操作,那么你可以这样配置:"preSql":["delete from 表名"],效果是:在执行到每个表写入数据前,会先执行对应的 delete from 对应表名称
o 必选:否
o 默认值:无
• postSql
o 描述:写入数据到目的表后,会执行这里的标准语句。(原理同 preSql )
o 必选:否
o 默认值:无
• writeMode
o 描述:控制写入数据到目标表采用 insert into 或者 replace into 或者 ON DUPLICATE KEY UPDATE 语句
o 必选:是
o 所有选项:insert/replace/update
o 默认值:insert
• batchSize
o 描述:一次性批量提交的记录数大小,该值可以极大减少DataX与Mysql的网络交互次数,并提升整体吞吐量。但是该值设置过大可能会造成DataX运行进程OOM情况。
o 必选:否
o 默认值:1024
类似 MysqlReader ,目前 MysqlWriter 支持大部分 Mysql 类型,但也存在部分个别类型没有支持的情况,请注意检查你的类型。
下面列出 MysqlWriter 针对 Mysql 类型转换列表:
• bit类型目前是未定义类型转换
Q: MysqlWriter 执行 postSql 语句报错,那么数据导入到目标数据库了吗?
A: DataX 导入过程存在三块逻辑,pre 操作、导入操作、post 操作,其中任意一环报错,DataX 作业报错。由于 DataX 不能保证在同一个事务完成上述几个操作,因此有可能数据已经落入到目标端。
Q: 按照上述说法,那么有部分脏数据导入数据库,如果影响到线上数据库怎么办?
A: 目前有两种解法,第一种配置 pre 语句,该 sql 可以清理当天导入数据, DataX 每次导入时候可以把上次清理干净并导入完整数据。第二种,向临时表导入数据,完成后再 rename 到线上表。
Q: 上面第二种方法可以避免对线上数据造成影响,那我具体怎样操作?
A: 可以配置临时表导入
接下来将mysql数据库中的数据写入hive的案例:
mysql数据库和表准备:
CREATE DATABASE `complaint_report` DEFAULT CHARACTER SET utf8;
USE `complaint_report`;
DROP TABLE IF EXISTS `sys_complaint_threshold_value`;
CREATE TABLE `sys_complaint_threshold_value` (
`id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`threshold_type` VARCHAR(16) DEFAULT NULL,
`threshold_name` VARCHAR(32) DEFAULT NULL,
`threshold_value` SMALLINT(2) DEFAULT '0',
`threshold_key` VARCHAR(32) DEFAULT NULL,
`operator_msg` VARCHAR(32) DEFAULT NULL,
`operator_scope` VARCHAR(16) DEFAULT NULL,
`create_date` DATETIME DEFAULT NULL,
`create_user` VARCHAR(32) DEFAULT NULL,
`update_date` DATETIME DEFAULT NULL,
`update_user` VARCHAR(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
Hive中创建库test_db和表sys_complaint_threshold_value:
use test_db;
drop table if exists sys_complaint_threshold_value;
CREATE TABLE `sys_complaint_threshold_value`(
`id` bigint,
`threshold_type` string,
`threshold_name` string,
`threshold_value` int
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS ORC;
编写json文件:
{
"job": {
"setting": {
"speed": {
"channel": 3
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "123456",
"column": [
"id",
"threshold_type",
"threshold_name",
"threshold_value"
],
"splitPk": "id",
"connection": [
{
"table": [
"sys_complaint_threshold_value"
],
"jdbcUrl": [
"jdbc:mysql://192.168.106.158:3306/complaint_report"
]
}
]
}
},
"writer": {
"name": "hdfswriter",
"parameter": {
"defaultFS":"hdfs://hadoop1:9000",
"fileType":"orc",
"path":"/user/hive/warehouse/test_db.db/sys_complaint_threshold_value",
"fileName":"sys_complaint_threshold_value",
"column":[
{
"name":"id",
"type":"BIGINT"
},
{
"name":"threshold_type",
"type":"STRING"
},
{
"name":"threshold_name",
"type":"STRING"
},
{
"name":"threshold_value",
"type": "INT"
}
],
"writeMode": "append",
"fieldDelimiter": "\t",
"compress":"NONE"
}
}
}
]
}
}
然后执行datax命令:
cd /home/installed/datax/bin/
python datax.py /home/test/dataxtest/mysql2hdfs.json
然后到hive中查看状态:
hive> use test_db;
OK
Time taken: 0.045 seconds
hive> drop table if exists sys_complaint_threshold_value;
OK
Time taken: 1.739 seconds
hive> CREATE TABLE `sys_complaint_threshold_value`(
> `id` bigint,
> `threshold_type` string,
> `threshold_name` string,
> `threshold_value` int
> )
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> STORED AS ORC;
OK
Time taken: 0.254 seconds
hive> select * from sys_complaint_threshold_value;
OK
5 tag 疑似虚假值 70
7 tag 职业索赔人值 81
8 tag 职业索赔人值 80
4 tag 聚类相关值 70
2 tag 疑似重复值 84
3 tag 聚类相关值 85
1 remind 疑似重复值 85
6 tag 重大风险值 60
Time taken: 0.221 seconds, Fetched: 8 row(s)
hive>