datax使用小记

DataX

DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、DRDS 等各种异构数据源之间高效的数据同步功能。

详细介绍见 https://github.com/alibaba/DataX/blob/master/introduction.md ,本文不对DataX的基本情况进行介绍,主要记录几个注意事项

应用

本次在公司项目中主要用来进行oracle到oracle的数据同步工作,将研究过程记录于此。

OracleReader插件详细介绍:https://github.com/alibaba/DataX/blob/master/oraclereader/doc/oraclereader.md

OracleWriter插件详细介绍:https://github.com/alibaba/DataX/blob/master/oraclewriter/doc/oraclewriter.md

注意事项

1、Oracle同步不支持更新操作,因为OracleWriter只支持insert into…(当主键/唯一性索引冲突时会写不进去冲突的行),mysql支持replace into(也就是更新),也就是Mysql支持更新,Oracle不支持更新。那么增量同步在Oracle这里只能是流水型数据。

2、preSql说明:job对应的json文件中,connection中的table必须是数据库存在的表,否则连接错误。执行顺序是先连表,再执行preSql,因此如果全量同步时,如果需要临时表,则需要额外编写程序完成操作。

3、postSql说明:在同步任务完成后可以进行的操作,如删除原表,更新临时表名为原表名,实现全量同步的同时,尽可能减小对原系统的影响。

4、可以配置出错限制条件,当数据出错超过限制条件时,程序会结束执行,但已开启的同步通道还会继续执行到完成

"errorLimit": {
    //先选择record
    "record": 0,
    //百分比  1表示100%
    "percentage": 0.02
}

5、splitPk:OracleReader插件中会有此参数,如果指定splitPk,表示用户希望使用splitPk代表的字段进行数据分片,DataX因此会启动并发任务进行数据同步,这样可以大大提供数据同步的效能。
推荐splitPk用户使用表主键,因为表主键通常情况下比较均匀,因此切分出来的分片也不容易出现数据热点。目前splitPk仅支持整形、字符串型数据切分,splitPk如果不填写,将视作用户不对单表进行切分,OracleReader使用单通道同步全量数据。
该处由于业务需求,想知道具体是如何根据 splitPk 进行数据切分的,看源码得知:

  • 首先计算需要将数据切分的份数,对单表会根据设置的 channel数 * 5 得到
    源码在 DataX-master\plugin-rdbms-util\src\main\java\com\alibaba\datax\plugin\rdbms\reader\util\ReaderSplitUtil.java 类中doSplit 方法内,eachTableShouldSplittedNumber = eachTableShouldSplittedNumber * 5;

  • 会首先根据指定的 splitPk 和 上一步得到的切分份数 进行抽样,sql如下:
    SELECT * FROM ( SELECT ID FROM REG_MARPRIPINFO SAMPLE (0.1) WHERE (ID IS NOT NULL) ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM <= 40 ORDER by ID ASC;
    ID是设置的splitPk,40是设置了 channel=8计算得到。
    从这里可以看出对表的切割不是均分,而是随机抽样的结果,无论是整形、字符串型都是该方式划分区间。
    暂不确定SAMPLE是否对视图生效

6、日志输出问题,日志文件名的设置方式在 datax.py 中,具体代码如下:

# jobResource 可能是 URL,也可能是本地文件路径(相对,绝对)
jobResource = args[0]
if not isUrl(jobResource):
    jobResource = os.path.abspath(jobResource)
    if jobResource.lower().startswith("file://"):
        jobResource = jobResource[len("file://"):]

jobParams = ("-Dlog.file.name=%s") % (jobResource[-20:].replace('/', '_').replace('.', '_'))

可以看到取了路径的后20个字符作为日志名,因此就会发现默认生成的日志名是混乱的,另外日志文件名后的时间戳是在由java代码控制的,配置文件在datax/conf/logback.xml内。见下图
在这里插入图片描述

图中我将控制台的日志输出进行了关闭,同时日志文件的时间戳不再由java代码控制,改为python代码控制

如果要以job对应的json名作为日志文件名,并添加时间戳,可参考下边代码:

jobResource = args[0]
if not isUrl(jobResource):
    jobResource = os.path.abspath(jobResource)
    if jobResource.lower().startswith("file://"):
        jobResource = jobResource[len("file://"):]
# print(jobResource)
o_file_name = jobResource.split("/")[-1].replace('.', '_')
timestamp = datetime.datetime.now().strftime("%H_%M_%S.%f")[:-3]  # 注意导包 import datetime
file_name = o_file_name + "-" + timestamp
print(file_name)
# 给文件后缀添加时间戳
jobParams = ("-Dlog.file.name=%s") % (file_name)

生成的日志文件名如下图所示:
在这里插入图片描述

7、python3启动datax.py,参考:https://github.com/WeiYe-Jing/datax-web/tree/master/doc/datax-web/datax-python3 将其中的三个文件替换原始的 datax/bin目录下的三个即可

8、datax的程序是通过datax.py启动的,是通过python的开启子进程调用执行的

9、idea中远程调试代码方法参考该文:https://www.kanzhun.com/jiaocheng/167192.html

10、读取oracle的数据,并非采用分页方式,而是通过指定jdbc的fetchSize参数来实现,可参考 https://www.cnblogs.com/baimingqian/p/11761942.html 的介绍,查询数据的源码如下:

	rs = DBUtil.query(conn, querySql, fetchSize); 
	// query 底层代码如下:
    public static ResultSet query(Connection conn, String sql, int fetchSize, int queryTimeout)
            throws SQLException {
        // make sure autocommit is off
        conn.setAutoCommit(false);
        Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY);
        stmt.setFetchSize(fetchSize);
        stmt.setQueryTimeout(queryTimeout);
        return query(stmt, sql);
    }
    // 不断获取数据,transportOneRecord 用来生成一条记录并交给writer执行写入操作
    while (rs.next()) {
        rsNextUsedTime += (System.nanoTime() - lastTime);
        this.transportOneRecord(recordSender, rs,
                metaData, columnNumber, mandatoryEncoding, taskPluginCollector);
        lastTime = System.nanoTime();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章