開心一刻
中午我媽微信給我訊息
媽:兒子啊,媽電話欠費了,能幫媽充個話費嗎
我:媽,我知道了,我幫你充
當我幫我媽把話費充好,正準備回微信的時候,我媽微信給我發訊息了
媽:等會兒子,不用充了,剛剛有個二臂幫媽充上了
我輸入框中的(媽,充好了)是發還是不發?
簡單使用
關於 DataX
,大家可以去看官網介紹:introduction
裡面講到了 DataX
的概況、框架設計、核心架構、外掛體系、核心優勢,由阿里出品,並在阿里內部被廣泛使用,其效能、穩定都是經過了嚴格考驗的。得益於它的框架設計
- Reader:資料採集模組,負責採集源資料來源的資料,並將資料傳送給 FrameWork
- Writer:資料寫入模組,不斷從 FrameWork 取資料,並將資料寫入目標資料來源
- FrameWork:核心模組,用於連線 Reader 和 Writer,作為兩者的資料傳輸通道,並處理緩衝、流控、併發、資料轉換等核心問題
我們很容易實現二次開發,當然主要是針對新外掛的開發。DataX
已經實現了非常多的外掛
型別 | 資料來源 | Reader(讀) | Writer(寫) | 文件 |
---|---|---|---|---|
RDBMS 關係型資料庫 | MySQL | √ | √ | 讀 、寫 |
Oracle | √ | √ | 讀 、寫 | |
OceanBase | √ | √ | 讀 、寫 | |
SQLServer | √ | √ | 讀 、寫 | |
PostgreSQL | √ | √ | 讀 、寫 | |
DRDS | √ | √ | 讀 、寫 | |
Kingbase | √ | √ | 讀 、寫 | |
通用RDBMS(支援所有關係型資料庫) | √ | √ | 讀 、寫 | |
阿里雲數倉資料儲存 | ODPS | √ | √ | 讀 、寫 |
ADB | √ | 寫 | ||
ADS | √ | 寫 | ||
OSS | √ | √ | 讀 、寫 | |
OCS | √ | 寫 | ||
Hologres | √ | 寫 | ||
AnalyticDB For PostgreSQL | √ | 寫 | ||
阿里雲中介軟體 | datahub | √ | √ | 讀 、寫 |
SLS | √ | √ | 讀 、寫 | |
圖資料庫 | 阿里雲 GDB | √ | √ | 讀 、寫 |
Neo4j | √ | 寫 | ||
NoSQL資料儲存 | OTS | √ | √ | 讀 、寫 |
Hbase0.94 | √ | √ | 讀 、寫 | |
Hbase1.1 | √ | √ | 讀 、寫 | |
Phoenix4.x | √ | √ | 讀 、寫 | |
Phoenix5.x | √ | √ | 讀 、寫 | |
MongoDB | √ | √ | 讀 、寫 | |
Cassandra | √ | √ | 讀 、寫 | |
數倉資料儲存 | StarRocks | √ | √ | 讀 、寫 |
ApacheDoris | √ | 寫 | ||
ClickHouse | √ | √ | 讀 、寫 | |
Databend | √ | 寫 | ||
Hive | √ | √ | 讀 、寫 | |
kudu | √ | 寫 | ||
selectdb | √ | 寫 | ||
無結構化資料儲存 | TxtFile | √ | √ | 讀 、寫 |
FTP | √ | √ | 讀 、寫 | |
HDFS | √ | √ | 讀 、寫 | |
Elasticsearch | √ | 寫 | ||
時間序列資料庫 | OpenTSDB | √ | 讀 | |
TSDB | √ | √ | 讀 、寫 | |
TDengine | √ | √ | 讀 、寫 |
囊括了絕大部分資料來源,我們直接拿來用就行;如果如上資料來源都未包括你們需要的資料來源,你們也可以自實現外掛,參考 DataX外掛開發寶典 即可
如果只是使用 DataX
,那下載 DataX 工具包 即可,解壓之後目錄結構如下
每個資料夾的作用就不做介紹了,大家去看官網看文件就行;透過 bin
目錄下的 datax.py
啟動 DataX
。
現有 MySQL
資料庫 qsl_datax
,其上有表 qsl_datax_source
CREATE TABLE `qsl_datax_source` (
`id` bigint(20) NOT NULL COMMENT '自增主鍵',
`username` varchar(255) NOT NULL COMMENT '姓名',
`password` varchar(255) NOT NULL COMMENT '密碼',
`birth_day` date NOT NULL COMMENT '出生日期',
`remark` text,
PRIMARY KEY (`id`)
);
insert into `qsl_datax_source`(`id`, `username`, `password`, `birth_day`, `remark`) values
(1, '張三', 'z123456', '1991-01-01', '張三'),
(2, '李四', 'l123456', '1992-01-01', '李四'),
(3, '王五', 'w123456', '1993-01-01', '王五'),
(4, '麻子', 'm123456', '1994-01-01', '麻子');
需要將表中資料同步到 MySQL
資料庫 qsl_datax_sync
的表 qsl_datax_target
CREATE TABLE `qsl_datax_target` (
`id` bigint(20) NOT NULL COMMENT '自增主鍵',
`username` varchar(255) NOT NULL COMMENT '姓名',
`pw` varchar(255) NOT NULL COMMENT '密碼',
`birth_day` date NOT NULL COMMENT '出生日期',
`note` text,
PRIMARY KEY (`id`)
);
該如何實現?
-
配置 job.json
因為是從
MySQL
同步到MySQL
,所以我們的Reader
是MySQL
,Writer
也是MySQL
,那麼配置檔案從哪複製也就清楚了。從 MysqlReader 複製Reader
配置,從 MysqlWriter 複製Writer
配置,然後將相關引數值配置成我們自己的,mysql2Mysql.json
就算配置完成{ "job": { "setting": { "speed": { "channel": 5 }, "errorLimit": { "record": 0, "percentage": 0.02 } }, "content": [ { "reader": { "name": "mysqlreader", "parameter": { "username": "root", "password": "123456", "column": [ "id", "username", "password", "birth_day", "remark" ], "connection": [ { "jdbcUrl": [ "jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&characterEncoding=utf-8" ], "table": [ "qsl_datax_source" ] } ] } }, "writer": { "name": "mysqlwriter", "parameter": { "writeMode": "insert", "username": "root", "password": "123456", "column": [ "id", "username", "pw", "birth_day", "note" ], "connection": [ { "jdbcUrl": "jdbc:mysql://192.168.2.118:3306/qsl_datax_sync?useUnicode=true&characterEncoding=utf-8", "table": [ "qsl_datax_target" ] } ] } } } ] } }
mysql2Mysql.json
存放到哪都可以,推薦大家放到DataX
的job
目錄下,方便管理。配置不算複雜,相信大家都能看懂 -
啟動
DataX
進行同步到
DataX
的bin
目錄下啟動命令列視窗,然後執行如下命令python datax.py ../job/mysql2Mysql.json
當我們看到如下輸出,就說明同步成功了
需要說明的是
DataX 不支援表結構同步,只支援資料同步,所以同步的時候需要保證目標表已經存在
column
指的就是 job.json
中 reader
和 writer
節點下的 column
,配置需要同步的列名集合;可以配置表的列名,也可以配置常量、表示式,還可以配置 *
,但不推薦配置 *
,因為它不便於我們檢視列之間的對映關係
Reader
和 Writer
之間的列是根據順序進行對映的,而非根據欄位名進行對映的,以前面的 mysql2Mysql.json
為例,欄位的對映關係如下所示
相當於是根據陣列的索引進行對映的,reader_column[n]
對映 writer_column[n]
,那麼問題來了,如果列數不對應會怎麼樣
-
Reader
列數比Writer
多去掉
Writer
的列pw
,然後執行下同步任務,會發現同步異常,提示如下資訊列配置資訊有錯誤. 因為您配置的任務中,源頭讀取欄位數:4 與 目的表要寫入的欄位數:5 不相等. 請檢查您的配置並作出修改.
-
Reader
列數比Writer
少同樣會同步異常,提示資訊類似如下
列配置資訊有錯誤. 因為您配置的任務中,源頭讀取欄位數:4 與 目的表要寫入的欄位數:5 不相等. 請檢查您的配置並作出修改.
如果列數一致,但列的順序沒有正確對映,會出現什麼情況
-
同步異常
你們是不是有這樣的疑問:列數一樣,怎麼會同步異常?因為存在列型別不匹配,導致資料插不進去,例如我將
Writer
中的username
和birth_day
對調下位置,然後執行同步,會發現同步異常,異常資訊類似如下Date 型別轉換錯誤
-
同步正常,資料卻亂了
對調下
Writer
的username
和pw
執行同步任務,會發現同步沒有出現異常,但你們看一眼目標資料來源的資料
很明顯髒資料了,這算同步成功還是同步失敗?
示例的髒資料很容易能夠看出來,如果出現兩列很類似的資料,那就麻煩了,等待我們的就是長夜漫漫的
bug
排查之旅
table
在 Reader
表示從哪讀資料,在 Writer
表示往哪寫資料;Reader
和 Writer
都支援配置多個表,但需要保證這些表是同一 schema
結構
個人非常不推薦一個 job
配置多個 table
,而是一個 job
一個 table
,如果需要同步多個 table
,那就配置多個 job
嘛
splitPk
這個配置只針對 Reader
Reader
進行資料抽取時,如果指定了 splitPk
,那麼 DataX
會按 splitPk
配置的欄位進行資料分片,啟動併發任務進行資料同步,從而提高同步的效率
那問題又來了,分成多少片了?我已經給大家總結好了
若未配置
splitPk
,則一個table
對應一個task
配置了
splitPk
,table
只要 1 個,則分成job.setting.speed.channel * reader.parameter.splitFactor
片,每片對應一個task
splitFactor
未配置的情況下,其預設值是 5配置了
splitPk
,且table
多餘 1 個,則對每個table
分成job.setting.speed.channel
片,每片對應一個task
不推薦大家在一個
job
中配置多個表,所以這種情況瞭解就好
比較可惜的是,目前 splitPk
僅支援整形資料切分,否則會報錯
我們對 mysql2Mysql.json
進行下 splitPk
改造,調整如下 2 項,其他不動
- job.setting.speed.channel 調整成 2
- reader 節點下新增 2 配置項
- reader.parameter.splitPk="id"
- reader.parameter.splitFactor=2
執行同步任務,能看到如下日誌
仔細看 allQuerySql
,4 條 SQL
代表 4 個分片,這個我相信你們都能理解,但是 where id IS NULL
這條 SQL
是什麼意思?其實我們仔細思考下就明白了,我們之所以認為 where id IS NULL
沒必要存在的原因是我們知道 id
是主鍵,但 DataX
知道嗎,它不知道,所以需要 where id IS NULL
來保證資料不被遺漏。不過話說回來,資料量少的時候,不分片效率比分片要高,這又回到了那個老生常談的問題了
多執行緒一定比單執行緒效率高嗎
where
同樣只針對 Reader
同 SQL
中的 WHERE
一樣,是篩選條件,Reader
根據 column
、table
、where
拼接 SQL
,然後用這個拼接好的 SQL
進行資料抽取。示例演示之前,我們記得將 mysql2Mysql.json
還原成最初的樣子,然後補上 where
條件
{
"job": {
"setting": {
"speed": {
"channel": 3
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "123456",
"column": [
"id",
"username",
"password",
"birth_day",
"remark"
],
"connection": [
{
"jdbcUrl": [
"jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&characterEncoding=utf-8"
],
"table": [
"qsl_datax_source"
]
}
],
"where": "id < 3"
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"writeMode": "insert",
"username": "root",
"password": "123456",
"column": [
"id",
"username",
"pw",
"birth_day",
"note"
],
"connection": [
{
"jdbcUrl": "jdbc:mysql://192.168.2.118:3306/qsl_datax_sync?useUnicode=true&characterEncoding=utf-8",
"table": [
"qsl_datax_target"
]
}
]
}
}
}
]
}
}
執行同步程式,會在日誌中看到如下資訊
如果再加上 splitPk
,你們能想到 DataX
的處理邏輯嗎,我給你們看一段日誌
這段日誌,你們看明白了嗎
如果不配置 where
或者 where
的值配置空,那麼就相當於全量同步;如果正常配置了 where
則相當於增量同步,而這個增量同步是在實際專案中用的比較多的。一旦涉及得到增量,我們是不是得把增量列的值以變數的形式傳入值,而 DataX
正好實現了該功能,類似如下進行配置
"where": "id > $startId"
透過啟動命令來傳入變數值,類似如下
python datax.py ../job/mysql2Mysql.json -p"-DstartId=1"
同步任務出現如下日誌,說明變數的值傳入正常
再結合排程平臺,那麼定時增量同步就實現了
有興趣的可以去看看 datax-web
querySql
只針對 Reader
table
加 where
能配置的篩選條件還是比較有限,join
也沒法滿足,所以 querySql
應運而生。querySql
允許使用者自定義篩選 SQL
當使用者配置
querySql
時,Reader
直接忽略table
、column
、where
條件的配置,querySql
優先順序大於table
、column
、where
選項
table
和querySql
只能配置一個,不能同時配置
querySql
同樣支援變數,類似如下
{
"job": {
"setting": {
"speed": {
"channel": 3
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "123456",
"splitPk": "id"
"splitFactor": 2
"connection": [
{
"querySql": ["select id,username,password,birth_day, 'remark' AS remark from qsl_datax_source where id > $startId"]
"jdbcUrl": [
"jdbc:mysql://192.168.2.118:3307/qsl_datax?useUnicode=true&characterEncoding=utf-8"
],
}
]
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"writeMode": "insert",
"username": "root",
"password": "123456",
"column": [
"id",
"username",
"pw",
"birth_day",
"note"
],
"connection": [
{
"jdbcUrl": "jdbc:mysql://192.168.2.118:3306/qsl_datax_sync?useUnicode=true&characterEncoding=utf-8",
"table": [
"qsl_datax_target"
]
}
]
}
}
}
]
}
}
同步日誌中會出現如下資訊
大家可以看到,如果配置了 querySql
,那麼 splitPk
配置就不生效了
總結
- 大家如果細心的話,會發現我講得基本都是關於
Reader
,實際也確實是Reader
配置要複雜很多,至於Writer
配置嘛,我相信你們都能看懂,也都會配置,我就不嘮叨了 column
不推薦配置*
,推薦配列名,能更直觀的反應對映關係table
模式下,單job
推薦只配一個table
,如果是同步多個table
, 推薦配置多個job
splitPk
只支援table
模式,實現分片併發獲取資料,提高查詢效率,但這不是絕對的,小資料量的情況下,可能單任務效率更高where
只支援table
模式,給查詢增加過濾條件,支援變數,可以實現增量同步querySql
模式下,table
模式不能配置,否則異常,column
、where
、splitPk
即使配置了也不生效;querySql
可以實現使用者自定義SQL
,非常靈活,join
查詢就可以用querySql
來實現