电商数仓学习-DataX的使用

全量表同步工具DataX

  • 前言
  • 一、DataX简介
    • 1.DataX概述
    • 2.DataX支持的数据源
  • 二、DataX架构原理
    • 1.DataX设计理念
    • 2.DataX框架设计
    • 3.DataX运行流程
    • 4.DataX调度决策思路
    • 5.DataX和Sqoop对比
  • 三、DataX部署
    • 1.下载安装
  • 四、DataX使用
    • 1.DataX任务提交命令
    • 2.DataX配置文件格式
    • 3.DataX传参
  • 五、DataX案例
    • 1.同步MySQL数据到HDFS案例
        • 1)使用TableMode方式实现
        • 2)TableMode方式的参数说明
        • 3)使用QuerySQLMode方式实现
        • 4)QuerySQLMode配置说明
        • 5)提交运行(两种方式都一样)
        • 6)两种方式对比
    • 2.同步HDFS数据到MySQL案例
        • 1)配置文件编写
        • 2)配置文件参数说明
        • 3)提交运行
  • 六、DataX优化
    • 1.速度控制
    • 2.内存调整

前言

前面已经说明全量表适用DataX工具进行同步,因此对DataX进行一个简单的学习

一、DataX简介

1.DataX概述

       DataX 是一个离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。

2.DataX支持的数据源

电商数仓学习-DataX的使用_第1张图片
从图上看,数仓用到的数据源基本上都支持。

二、DataX架构原理

1.DataX设计理念

       为了解决异构数据源(异构数据源指的是相同的数据在不同的地方存储的结构不同)同步问题,DataX将复杂的网状的同步链路变成了星型数据链路,DataX作为中间传输载体负责连接各种数据源。当需要接入一个新的数据源的时候,只需要将此数据源对接到DataX,便能跟已有的数据源做到无缝数据同步(这里不管是从哪里读的数据,统统转化为DataX规定的结构,再根据要写入的数据源的类型,转化为对应的结构)。

2.DataX框架设计

       DataX本身作为离线数据同步框架,采用Framework + plugin架构构建。将数据源读取和写入抽象成为Reader/Writer插件,纳入到整个同步框架中。
电商数仓学习-DataX的使用_第2张图片
FrameWork是整个的核心,不管数据源从哪来,到这里都转化为固定的数据结构
PS:流控:速度的控制

3.DataX运行流程

下图是一个DataX作业生命周期的时序图:
电商数仓学习-DataX的使用_第3张图片
一个Job是一个进程,一个Task是一个线程

4.DataX调度决策思路

举一个例子,用户提交了一个DataX作业(一个Job),并且配置了总的并发度为20,目的是对一个有100张分表(默认1张表为一个Task,实际上一张表可以继续切分为多个Task)的mysql数据源进行同步。DataX的调度决策思路是:
1)DataX Job根据分库分表切分策略,将同步工作分成100个Task。
2)根据配置的总的并发度20(可以同时运行20个Task),以及每个Task Group的并发度5(每个Task Group可以同时运行5个Task),DataX计算共需要分配4个TaskGroup。
3)4个TaskGroup平分100个Task,每一个TaskGroup负责运行25个Task。

5.DataX和Sqoop对比

功能 DataX Sqoop
运行模式 单进程多线程 MR
分布式 不支持,可以通过调度系统规避 支持(MR就是分布式)
流控 有流控功能 需要定制
统计信息 已有一些统计,上报需定制 没有,分布式的数据收集不方便
数据校验 在core部分有校验功能 没有,分布式的数据收集不方便
监控 需要定制 需要定制

综上,DataX功能更加强大,速度更加快,但是DataX对于数据格式的支持较少(只支持gzip压缩格式,lzo等都不支持)

三、DataX部署

1.下载安装

第一步,先下载,下载地址:http://datax-opensource.oss-cn-hangzhou.aliyuncs.com/datax.tar.gz
第二步,解压:tar -zxvf datax.tar.gz -C /opt/module/
第三步,自检:python /opt/module/datax/bin/datax.py /opt/module/datax/job/job.json
出现如下内容,则表明安装成功:
电商数仓学习-DataX的使用_第4张图片

四、DataX使用

1.DataX任务提交命令

命令:python bin/datax.py path/to/your/job.json (job.json是自己编写的同步文件)

2.DataX配置文件格式

查看DataX配置文件模板命令:python bin/datax.py -r mysqlreader -w hdfswriter
上面的mysqlreader和hdfswriter可以根据自己的需要修改为对应的输入源和输出源
电商数仓学习-DataX的使用_第5张图片
上图是查询给出的模板,json最外层是一个job,job包含setting和content两部分,setting是对整个job的配置,content是用于配置数据源和数据的目的地。
还可以通过官方文档查看对应的Reader和Writer的具体参数:https://github.com/alibaba/DataX/blob/master/README.md https://gitee.com/mirrors/DataX/blob/master/README.md
电商数仓学习-DataX的使用_第6张图片
点击对应的读、写,可以查看对应的参数

3.DataX传参

       通常情况下,离线数据同步任务需要每日定时重复执行,故HDFS上的目标路径通常会包含一层日期,以对每日同步的数据加以区分,也就是说每日同步数据的目标路径不是固定不变的,因此DataX配置文件中HDFS Writer的path参数的值应该是动态的。为实现这一效果,就需要使用DataX传参的功能。
DataX传参的用法如下,在JSON配置文件中使用${param}引用参数,在提交任务时使用-p"-Dparam=value"传入参数值,具体示例如下:
在需要动态传入参数的地方这样写:

	"fileType": "text",
    "path": "/base_province/${dt}",
    "writeMode": "append"

其中dt就是要传入的参数名
在提交任务时,使用命令:python bin/datax.py -p"-Ddt=2020-06-14" job/base_province.json

五、DataX案例

1.同步MySQL数据到HDFS案例

案例需求:同步gmall数据库中base_province表数据到HDFS的/base_province目录
需求分析:要实现该功能,需选用MySQLReader和HDFSWriter,MySQLReader具有两种模式分别是TableMode和QuerySQLMode,前者使用table,column,where等属性声明需要同步的数据;后者使用一条SQL查询语句声明需要同步的数据。

1)使用TableMode方式实现

首先,创建配置文件:vim /opt/module/datax/job/base_province.json
编写配置文件:

{
    "job": {
        "setting": {
            "speed": {
                 "channel": 1
            }
        },
        "content": [
            {
                "reader": {
                    "name": "mysqlreader",
                    "parameter": {
                        "username": "root",
                        "password": "123456",
                        "column": [
                            "id",
                            "name",
                            "region_id",
                            "area_code",
                            "iso_code",
                            "iso_3166_2"
                        ],
                        "where":"id>=3",
                        "splitPk": "id",
                        "connection": [
                            {
                                "table": [
                                    "base_province"
                                ],
                                "jdbcUrl": [
                                    "jdbc:mysql://hadoop102:3306/gamll"
                                ]
                            }
                        ]
                    }
                },
               "writer": {
                    "name": "hdfswriter",
                    "parameter": {
                        "defaultFS": "hdfs://hadoop102:8020",
                        "fileType": "text",
                        "path": "/base_province",
                        "fileName": "base_province",
                        "column": [
                            {
                                "name": "id",
                                "type": "bigint"
                            },
                            {
                                "name": "name",
                                "type": "string"
                            },
                            {
                                "name": "region_id",
                                "type": "string"
                            },
                            {
                                "name": "area_code",
                                "type": "string"
                            },
                            {
                                "name": "iso_code",
                                "type": "string"
                            },
                            {
                                "name": "iso_3166_2",
                                "type": "string"
                            }
                        ],
                        "writeMode": "append",
                        "fieldDelimiter": "\t",
                        "compress":"gzip"
                    }
                }
            }
        ]
    }
}

注:mysqlreader里的jdbcUrl是一个数组,可以写多个url(阿里内部支持多个url,外部写一个即可),但是这里写多个的意思是一个数据库连接的多种参数形式,比如:"jdbc:mysql://bad_ip:3306/database", "jdbc:mysql://127.0.0.1:bad_port/database", "jdbc:mysql://127.0.0.1:3306/database"这三种形式是为了保障至少有一个能连接上这个数据库,而不支持连接多个数据库。
hdfswriter里的writeMode参数为append时,写入数据不做任何处理,会在fileName后加一些字符,保证文件名不会冲突;参数为nonConflict时,如果目录下有fileName前缀的文件,直接报错。
最终结果:
电商数仓学习-DataX的使用_第7张图片
红色部分就是为了防止文件重复加的字符

2)TableMode方式的参数说明

Reader参数说明:电商数仓学习-DataX的使用_第8张图片
Writer参数说明:
电商数仓学习-DataX的使用_第9张图片
注意事项:
       HDFS Writer没有提供nullFormat参数,这意味着用户无法指定null值写到HDFS的存储格式。HDFS默认将null值存储为空字符串(""),而Hive默认的null值存储格式为\N,因此如果不对null值做处理,在查询表的时候会将null值显示为""。
解决方法一:修改HDFS Writer源码,增加自定义null值存储格式的逻辑,可以参考https://blog.csdn.net/u010834071/article/details/105506580(没有阅读代码的基础不推荐)
解决方法二:在Hive建表时自定义null值的存储格式为空字符串(推荐),如下:

DROP TABLE IF EXISTS base_province;
CREATE EXTERNAL TABLE base_province
(
    `id`         STRING COMMENT '编号',
    `name`       STRING COMMENT '省份名称',
    `region_id`  STRING COMMENT '地区ID',
    `area_code`  STRING COMMENT '地区编码',
    `iso_code`   STRING COMMENT '旧版ISO-3166-2编码,供可视化使用',
    `iso_3166_2` STRING COMMENT '新版IOS-3166-2编码,供可视化使用'
) COMMENT '省份表'
    ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    NULL DEFINED AS ''
    LOCATION '/base_province/';

NULL DEFINED AS ‘’ 这里将’'定义为null
PS:Hive默认使用Hadoop的压缩格式,因此可以查出来gzip类型的压缩文件中的数据,Hadoop不支持的压缩格式需要额外去写

 
Setting参数说明:
电商数仓学习-DataX的使用_第10张图片
上面的errorLimit一般不配,采用默认

3)使用QuerySQLMode方式实现

配置文件内容如下:

{
    "job": {
        "setting": {
            "speed": {
                 "channel": 1
            }
        },
        "content": [
            {
                "reader": {
                    "name": "mysqlreader",
                    "parameter": {
                        "username": "root",
                          "password": "123456",
                          "connection": [
                            {
                                "querySql": [
                                    "select id,name,region_id,area_code,iso_code,iso_3166_2 from base_province where id>=3;"
                                ],
                                "jdbcUrl": [
                                    "jdbc:mysql://hadoop102:3306/gamll"
                                ]
                            }
                        ]
                    }
                },
               "writer": {
                    "name": "hdfswriter",
                    "parameter": {
                        "defaultFS": "hdfs://hadoop102:8020",
                        "fileType": "text",
                        "path": "/base_province",
                        "fileName": "base_province",
                        "column": [
                            {
                                "name": "id",
                                "type": "bigint"
                            },
                            {
                                "name": "name",
                                "type": "string"
                            },
                            {
                                "name": "region_id",
                                "type": "string"
                            },
                            {
                                "name": "area_code",
                                "type": "string"
                            },
                            {
                                "name": "iso_code",
                                "type": "string"
                            },
                            {
                                "name": "iso_3166_2",
                                "type": "string"
                            }
                        ],
                        "writeMode": "append",
                        "fieldDelimiter": "\t",
                        "compress":"gzip"
                    }
                }
            }
        ]
    }
}

在使用了querySql后,第一种方式的table、column这些配置失效(一般直接删掉),即querySql的优先级大于column、where选项。

4)QuerySQLMode配置说明

电商数仓学习-DataX的使用_第11张图片

5)提交运行(两种方式都一样)

第一步,在向HDFS同步数据前,要确保目标路径已存在:hadoop fs -mkdir /base_province
第二步,进入DataX根目录,执行:python bin/datax.py job/base_province.json
第三步,查看DataX运行结果:

2021-10-13 11:13:14.930 [job-0] INFO  JobContainer - 
任务启动时刻                    : 2021-10-13 11:13:03
任务结束时刻                    : 2021-10-13 11:13:14
任务总计耗时                    :                 11s
任务平均流量                    :               66B/s
记录写入速度                    :              3rec/s
读出记录总数                    :                  32
读写失败总数                    :                   0

第四步,查看HDFS文件,命令(linux查看gzip文件命令):hadoop fs -cat /base_province/* | zcat

3	山西	1	140000	CN-14	CN-SX
4	内蒙古	1	150000	CN-15	CN-NM
5	河北	1	130000	CN-13	CN-HE
6	上海	2	310000	CN-31	CN-SH
7	江苏	2	320000	CN-32	CN-JS
8	浙江	2	330000	CN-33	CN-ZJ
9	安徽	2	340000	CN-34	CN-AH
10	福建	2	350000	CN-35	CN-FJ
11	江西	2	360000	CN-36	CN-JX
12	山东	2	370000	CN-37	CN-SD
14	台湾	2	710000	CN-71	CN-TW
15	黑龙江	3	230000	CN-23	CN-HL
16	吉林	3	220000	CN-22	CN-JL
17	辽宁	3	210000	CN-21	CN-LN
18	陕西	7	610000	CN-61	CN-SN
19	甘肃	7	620000	CN-62	CN-GS
20	青海	7	630000	CN-63	CN-QH
21	宁夏	7	640000	CN-64	CN-NX
22	新疆	7	650000	CN-65	CN-XJ
23	河南	4	410000	CN-41	CN-HA
24	湖北	4	420000	CN-42	CN-HB
25	湖南	4	430000	CN-43	CN-HN
26	广东	5	440000	CN-44	CN-GD
27	广西	5	450000	CN-45	CN-GX
28	海南	5	460000	CN-46	CN-HI
29	香港	5	810000	CN-91	CN-HK
30	澳门	5	820000	CN-92	CN-MO
31	四川	6	510000	CN-51	CN-SC
32	贵州	6	520000	CN-52	CN-GZ
33	云南	6	530000	CN-53	CN-YN
13	重庆	6	500000	CN-50	CN-CQ
34	西藏	6	540000	CN-54	CN-XZ

6)两种方式对比

方式 优点 缺点
TableMode 可以切分任务(channel并发度不能填1,splitPk要填值)
QuerySQLMode 固定不能切分任务,一个SQL语句不能切分,如果写多个才可能切分

2.同步HDFS数据到MySQL案例

案例要求:同步HDFS上的/base_province目录下的数据到MySQL gmall 数据库下的test_province表。
需求分析:要实现该功能,需选用HDFSReader和MySQLWriter。

1)配置文件编写

创建配置文件:vim /opt/module/datax/job/base_province.json
编写配置文件:

{
    "job": {
        "setting": {
            "speed": {
                "channel": 1
            }
        },
        "content": [
            {
                "reader": {
                    "name": "hdfsreader",
                    "parameter": {
                        "path": "/base_province",
                        "defaultFS": "hdfs://hadoop102:8020",
                        "column": [
                              "*"
                        ],
                        "fileType": "text",
                        "encoding": "UTF-8",
                        "fieldDelimiter": "\t",
                        "compress": "gzip",
                        "nullFormat": "\\N"
                    }
                },
                "writer": {
                    "name": "mysqlwriter",
                    "parameter": {
                        "writeMode": "replace",
                        "username": "root",
                        "password": "123456",
                        "column": [
                            "id",
                            "name",
                            "region_id",
                            "area_code",
                            "iso_code",
                            "iso_3166_2"
                        ],
                        "connection": [
                            {
                                "jdbcUrl": "jdbc:mysql://hadoop102:3306/gmall?useUnicode=true&characterEncoding=utf-8",
                                "table": [
                                    "test_province"
                                ]
                            }
                        ]
                    }
                }
            }
        ]
    }
}

2)配置文件参数说明

HDFS Reader参数说明:
电商数仓学习-DataX的使用_第12张图片
这里column中的列的类型是DataX里的类型,不是HDFS里的类型
nullFormat是将\N识别为null值
MySQL Writer参数说明:
电商数仓学习-DataX的使用_第13张图片
writeMode参数为insert时,当主键/唯一性索引冲突时会写不进去冲突的行;当参数为replace时,没有遇到主键/唯一性索引冲突时,与 insert into 行为一致,冲突时会用新行替换原有行所有字段。
注意:数据写入MySQL里的表时,要先确保这个表存在,若不存在,要先创建。

3)提交运行

第一步,在MySQL中创建gmall.test_province表:

DROP TABLE IF EXISTS `test_province`;
CREATE TABLE `test_province`  (
  `id` bigint(20) NOT NULL,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `region_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `area_code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `iso_code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `iso_3166_2` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

第二步,进入DataX个目录,执行命令:python bin/datax.py job/test_province.json
最后,查看DataX结果:

2021-10-13 15:21:35.006 [job-0] INFO  JobContainer - 
任务启动时刻                    : 2021-10-13 15:21:23
任务结束时刻                    : 2021-10-13 15:21:35
任务总计耗时                    :                 11s
任务平均流量                    :               70B/s
记录写入速度                    :              3rec/s
读出记录总数                    :                  34
读写失败总数                    :                   0

查看MySQL目标表数据:
电商数仓学习-DataX的使用_第14张图片

六、DataX优化

1.速度控制

       DataX提供了包括通道(并发)、记录流、字节流三种流控模式,可以随意控制你的作业速度,让你的作业在数据库可以承受的范围内达到最佳的同步速度。
关键优化参数如下:

参数 说明
job.setting.speed.channel 总并发数
job.setting.speed.record 总record限速
job.setting.speed.byte 总byte限速
core.transport.channel.speed.record 单个channel的record限速,默认值为10000(10000条/s)
core.transport.channel.speed.byte 单个channel的byte限速,默认值1024*1024(1M/s)

注意事项:
1)如果配置了总的record限速,就必须配置单个channel的record限速
2)如果配置了总的byte限速,就必须配置单个的channel的byte限速
3)如果配置了总的record和byte限速,channel并发数参数就会失效。因为配置了总record限速和总byte限速之后。实际channel并发数是通过计算得到的。

计算公式:
min(总byte限速/单个channel的byte限速,总record限速/单个channel的record限速)

例如设置channel为10,总record限速为80000,单个record限速为10000。首先,即使只设置channel为10,不设置别的,并发度也不一定正好为10,只是尽可能的贴近于这个值;其次因为总record限速80000,单个record限速10000,所以有8个record,小于10,限制了channel,最终并发度贴近于8。

配置实例:

{
    "core": {
        "transport": {
            "channel": {
                "speed": {
                    "byte": 1048576 //单个channel byte限速1M/s
                }
            }
        }
    },
    "job": {
        "setting": {
            "speed": {
                "byte" : 5242880 //总byte限速5M/s
            }
        },
        ...
    }
}

2.内存调整

       DataX Job内的Channel并发数提高时,内存的占用也会显著增加,因为DataX作为数据交换通道(数据源和目的地之间的通道),在内存中会缓存较多的数据。例如Channel中会有一个Buffer,作为临时的数据交换的缓冲区,而在部分Reader和Writer中,也会存在一些Buffer。因此为了防止OOM(内存溢出)等错误,需要调大JVM的堆内存。
第一种调整方式:直接更改datax.py脚本,找到-Xms(是JVM初始分配的内存,设置太大可能直接就起不来)和-Xmx(是JVM分配的最大内存)这两个地方,修改为需要的内存大小
第二种调整方式:在使用命令提交Job的时候,加上一个参数,例如python datax/bin/datax.py --jvm="-Xms8G -Xmx8G" /path/to/your/job.json
PS:内存一般可以设置为4G或者8G

你可能感兴趣的:(DataX,数仓同步工具,离线数仓,big,data)