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();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章