基于 DataX 完成數(shù)據(jù)訪問代理數(shù)據(jù)遷移
數(shù)據(jù)訪問代理(Open Database Proxy,簡稱 ODP)通過集成 DataX,支持全量離線靜態(tài)的數(shù)據(jù)遷移功能。DataX 是阿里巴巴集團內(nèi)被廣泛使用的離線數(shù)據(jù)同步工具/平臺,實現(xiàn)各種異構(gòu)數(shù)據(jù)源之間高效的數(shù)據(jù)同步。目前,支持的源端數(shù)據(jù)源類型依賴于 DataX 支持的類型,而目標(biāo)端僅支持 MySQL 和 OceanBase。
本文將引導(dǎo)您快速完成以下遷移任務(wù):
單庫單表 MySQL 遷移至 ODP
前置條件
您已經(jīng)開通數(shù)據(jù)訪問代理產(chǎn)品并購買了數(shù)據(jù)訪問代理實例,詳見 創(chuàng)建實例。
建庫建表
登錄數(shù)據(jù)訪問代理控制臺頁面,選擇 數(shù)據(jù)庫,單擊 創(chuàng)建數(shù)據(jù)庫。
在彈出的 創(chuàng)建數(shù)據(jù)庫 窗口中,選擇實例,單擊 創(chuàng)建。
進(jìn)入 選擇數(shù)據(jù)節(jié)點 頁面后,根據(jù)需要選擇 MySQL 或 OceanBase 的節(jié)點,單擊 下一步。
根據(jù)提示,填寫或選擇數(shù)據(jù)庫的基本信息。詳細(xì)參數(shù)信息,請參見 創(chuàng)建數(shù)據(jù)訪問代理數(shù)據(jù)庫。
數(shù)據(jù)庫創(chuàng)建完成后,進(jìn)入數(shù)據(jù)庫詳情頁,單擊右側(cè)頁面下方的 新增數(shù)據(jù)表。
在 新增數(shù)據(jù)表 頁面,輸入 數(shù)據(jù)表名,如
test_migration_user
。根據(jù)需要選擇表類型(單表或拆分表),此處以 拆分表 為例,并設(shè)置 分表總數(shù) 為 2。
配置分表規(guī)則,詳細(xì)配置方法可參見 創(chuàng)建數(shù)據(jù)訪問代理數(shù)據(jù)表 和 自定義分表規(guī)則。
勾選 現(xiàn)在創(chuàng)建物理表,單擊 下一步。
在 DDL 語句 中,輸入建表語句,示例如下:
CREATE TABLE `test_migration_user`( `user_id` varchar(16) NOT NULL, `username` varchar(64) NOT NULL, `id` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), UNIQUE KEY `uk_user_id`(`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4;
單擊 執(zhí)行,完成建表。
創(chuàng)建遷移賬戶
在數(shù)據(jù)訪問控制臺頁面,左側(cè)導(dǎo)航欄選擇 實例。
在實例列表中,找到剛剛創(chuàng)建的數(shù)據(jù)庫所在的實例,單擊實例名稱,進(jìn)入實例詳情頁。
切換至 賬號管理 頁簽,單擊 創(chuàng)建賬號。
在彈出的新窗口中,輸入數(shù)據(jù)庫賬號(必須是 odp_migrator)和賬號密碼,選擇相應(yīng)的授權(quán)數(shù)據(jù)庫。
單擊 確定,完成創(chuàng)建遷移賬戶。
配置連接參數(shù)
進(jìn)入數(shù)據(jù)庫詳情頁,選擇頁面下方的 連接參數(shù) 頁簽。
切換至 其他參數(shù) 后,在 connectionProperties 屬性欄,輸入以下屬性值:
rewriteBatchedStatements=true clobberStreamingResults=true
單擊底部 保存配置 按鈕。
準(zhǔn)備 DataX 環(huán)境
DataX 是一個異構(gòu)數(shù)據(jù)源間數(shù)據(jù)遷移的中間件,支持各種類型的 reader 和 writer。要實現(xiàn) ODP 數(shù)據(jù)遷移,您需要準(zhǔn)備 DataX 環(huán)境。
單擊此處 下載 DataX,并將其解壓至本地目錄。
單擊此處 下載 odpwriter 插件,并將其解壓至
$datax_dir/plugin/writer
目錄下。
有關(guān) DataX 的更多信息,參見 DataX 官方文檔。
編輯并執(zhí)行遷移 Job
進(jìn)入
$datax_dir/bin
目錄,編寫一份遷移 Job 描述文件。文件示例如下:{ "job": { "setting": { "speed": { "channel": 3 }, "errorLimit": { "record": 0, "percentage": 0.02 } }, "content": [ { "reader": { "name": "mysqlreader", "parameter": { "username": "$mysql_usr", "password": "$mysql_pwd", "column": [ "user_id", "username" ], "splitPk": "id", "connection": [ { "table": [ "user" ], "jdbcUrl": [ "jdbc:mysql://127.0.0.1:3306/test_migration" ] } ] } }, "writer": { "name": "odpwriter", "parameter": { "writeMode": "replace", "username": "odp_migrator", "password": "$odp_pwd", "column": [ "user_id", "username" ], "connection": [ { "jdbcUrl": "jdbc:mysql://$dbp_url/test_migration?useUnicode=true&characterEncoding=utf8", "table": [ "test_migration_user" ] } ] } } } ] } }
根據(jù)以上 Job 描述文件,該數(shù)據(jù)遷移任務(wù)是將單庫單表的 MySQL(
127.0.0.1:3306
)中的test_migration
庫里的user
表的數(shù)據(jù)(列user_id
,username
)遷移至$dbp_url
中的test_migration
庫里的test_migration_user
表(列user_id
,username
)。在
$datax_dir/bin
目錄下,執(zhí)行以下命令,運行數(shù)據(jù)遷移 Job:python datax.py $yourjob.json
命令執(zhí)行成功,即數(shù)據(jù)遷移完成。
ODP 遷移至其他數(shù)據(jù)庫
從 ODP 遷移至其他數(shù)據(jù)庫,操作步驟與 從 MySQL 遷移至 ODP 相似。
參考上文,完成 建庫建表、創(chuàng)建遷移賬戶、配置連接參數(shù)操作。
按照以下步驟,完成 DataX 環(huán)境準(zhǔn)備、Job 描述文件的編寫與執(zhí)行。
準(zhǔn)備 DataX 環(huán)境
單擊此處 下載 DataX,并將其解壓至本地目錄。
單擊此處 下載 odpreader 插件,并將其解壓至
$datax_dir/plugin/reader/
目錄下。
執(zhí)行 Job 描述文件
進(jìn)入
$datax_dir/bin
目錄,編寫一份遷移 Job 描述文件。文件示例如下:說明Reader 遷移賬號也必須是 odp_migrator。
對 Job 描述文件添加一個 connection 的校驗,僅允許配置一個 connection,且僅允許配置一張表。
{ "job": { "setting": { "speed": { "channel": 4 }, "errorLimit": { "record": 0, "percentage": 0.02 } }, "content": [ { "reader": { "name": "odpreader", "parameter": { "username": "odp_migrator", "password": "$odp_pwd", "column": [ "user_id", "gmt_create", "gmt_modified", "current_date", "current_time", "current_timestamp", "name", "is_ok", "age", "salary", "height", "memo", "character_stream", "binary_stream", ], "connection": [ { "table": [ "test_migration_user_large" ], "jdbcUrl": [ "jdbc:mysql://$odp_url:8066/test_join?useUnicode=true&characterEncoding=utf8" ] } ] } }, "writer": { "name": "odpwriter", "parameter": { "writeMode": "replace", "username": "odp_migrator", "password": "$odp_pwd", "column": [ "`user_id`", "`gmt_create`", "`gmt_modified`", "`current_date`", "`current_time`", "`current_timestamp`", "`name`", "`is_ok`", "`age`", "`salary`", "`height`", "`memo`", "`character_stream`", "`binary_stream`", ], "batchSize": 2048, "connection": [ { "jdbcUrl": "jdbc:mysql://$odp_url:8066/test_join?useUnicode=true&characterEncoding=utf8", "table": [ "test_migration_user_large_target" ] } ] } } } ] } }
在
$datax_dir/bin
目錄下,執(zhí)行如下命令,運行數(shù)據(jù)遷移 Job。python datax.py $yourjob.json
命令執(zhí)行成功,即數(shù)據(jù)遷移完成。
注意事項
不推薦使用 SCAN_ALL
hint + mysql reader 的方式進(jìn)行數(shù)據(jù)讀取。雖然這種方式也可以對分庫分表的數(shù)據(jù)表進(jìn)行數(shù)據(jù)抽取。但其數(shù)據(jù)拆分方式為 splitPK
,即全表掃描之后,根據(jù) ID 進(jìn)行拆分,拆分之后的每個子任務(wù) $from ~ $to 同樣需要全表掃描才能取出。這就意味著,任務(wù)拆分之后,每個子任務(wù)的查詢都是一次全表掃描。因此,這種方式性能差、容易超時,而且會對數(shù)據(jù)訪問代理實例產(chǎn)生較大的負(fù)載壓力,不建議使用。
相比之下,odpreader 的拆分方式是基于邏輯表的分表來實現(xiàn)的,如百庫百表下會拆分為 100 個子任務(wù),每個子任務(wù)的數(shù)據(jù)抽取僅會查詢單個分表,并不會產(chǎn)生全表掃描。因此,建議您使用 odpreader。
常見問題
DataX 支持的數(shù)據(jù)類型
DataX 的 MysqlReader 針對 MySQL 類型轉(zhuǎn)換列表如下:
DataX 內(nèi)部類型 | MySQL 數(shù)據(jù)類型 |
---|---|
long | int, tinyint, smallint, mediumint, int, bigint |
Double | float, double, decimal |
String | varchar, char, tinytext, text, mediumtext, longtext, year |
Date | date, datetime, timestamp, time |
Boolean | bit, bool |
Bytes | tinyblob, mediumblob, blob, longblob, varbinary |
除上述字段類型外,其他類型均不支持。
對于
tinyint(1)
,DataX 視為整型。對于
year
,DataX 視為字符串類型。對于
bit
,DataX 視為未定義行為。
事務(wù)與出錯重跑
在數(shù)據(jù)遷移過程中,可能存在部分?jǐn)?shù)據(jù)寫入失敗的情況,此時需要進(jìn)行重試。由于此時可能已經(jīng)有部分?jǐn)?shù)據(jù)已經(jīng)完成遷移,重試的時候回出現(xiàn) Duplicate Key 問題。此時,可以使用 DataX 的 REPLACE/INSERT IGNORE writeMode。
需要注意,REPLACE 語句的行為是如果發(fā)現(xiàn)主鍵或唯一鍵沖突,會將原來這條數(shù)據(jù)刪除,然后重新插入,這樣既可實現(xiàn)比較簡單的出錯重跑機制。REPLACE 語句可能會導(dǎo)致新的數(shù)據(jù)記錄的自增 id 有變化,如果使用自增 id 進(jìn)行關(guān)聯(lián),會出現(xiàn)問題。而 INSERT IGNORE 語句則不會有這個問題,如果發(fā)現(xiàn)主鍵或唯一鍵沖突,會忽略當(dāng)前這條 SQL 的插入。
超時問題
SocketTimeout 錯誤
現(xiàn)象:
出現(xiàn) SocketTimeout 報錯,類似的錯誤信息如下所示:
Thelast packet successfully received from the server was 5,004 milliseconds ago.Thelast packet sent successfully to the server was 5,004 milliseconds ago.
解決方案:
登錄數(shù)據(jù)訪問代理控制臺,進(jìn)行目標(biāo)數(shù)據(jù)庫的詳情頁。
選擇頁面下方的 連接參數(shù) 頁簽,在 其他參數(shù) > connectionProperties 屬性欄,添加如下屬性:
socketTimeout=5000(調(diào)整為更大的數(shù)值,默認(rèn)為5秒,單位為毫秒)
單擊 保存配置。
Timeout 錯誤
現(xiàn)象:
出現(xiàn) Timeout 報錯,對應(yīng)的錯誤碼為 4012。
原因:
該錯誤是 OceanBase 查詢超時問題。
解決方案:
您可以通過以下方法處理該錯誤:
在任意一個 column 中加入 hint:
/*+空格QUERY_TIMEOUT(111111111)空格*/ $columnName
,示例如下:"column":[ "/*+ QUERY_TIMEOUT(100) */ user_id", "username", "id", "gmt_create", ],
說明該超時時間僅影響當(dāng)前SQL,并不會影響其他SQL。
在 newConnectionSql 中添加
ob_query_timeout
參數(shù),單位為微秒。set@@ob_query_timeout=比較大的值
說明該參數(shù)配置將影響整個邏輯庫。在離線與在線業(yè)務(wù)混用 ODP 實例的場景中,不推薦使用這種參數(shù)配置。可以在直連物理庫時執(zhí)行這條 SQL,檢查該超時參數(shù)設(shè)置為多大值時不會超時,然后在此基礎(chǔ)上再加一些 buffer。
Communications link failure 錯誤
現(xiàn)象:
出現(xiàn) Communications link failure 報錯,錯誤信息如下所示:
Communications link failure
Thelast packet successfully received from the server was 0 milliseconds ago.Thelast packet sent successfully to the server was 605,920 milliseconds ago.
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:Communications link failure
Causedby: java.io.EOFException:Cannot read response from server.Expected to read 425 bytes, read 156 bytes before connection was unexpectedly lost.
原因:
該錯誤是因為數(shù)據(jù)庫達(dá)到了 net_write_timeout
而主動斷連導(dǎo)致的,即數(shù)據(jù)庫回寫超時。
解決方案:
數(shù)據(jù)遷移(流式讀取)時默認(rèn)值為 600 秒,您可以通過設(shè)置以下 ODP 連接參數(shù),解決該問題。
netTimeoutForStreamingResults=大于600的一個數(shù)值,單位是秒