TiDB DM踩坑實踐總結

1、 背景mysql

在早期從MySQL到TiDB實施同步操做過程當中,咱們大多數用的是mydumper+loader進行總體全量備份的導出,以後拿到meta信息後,經過syncer實現增量同步,總體操做起來比較麻煩,涉及的配置文件較多,其基本原理就是Syncer 經過把本身註冊爲一個 MySQL Slave 的方式,和 MySQL Master 進行通訊,而後不斷讀取 MySQL Binlog,進行 Binlog Event 解析,規則過濾和數據同步。其架構以下:
TiDB DM踩坑實踐總結git

然後pingcap官方推出了TiDB Data Migration (DM)套件,這一套件極大地下降了同步工具使用的門檻。
DM是一體化的數據遷移任務管理平臺,支持從 MySQL 或 MariaDB 到 TiDB 的全量數據遷移和增量數據複製。使用 DM 工具備利於簡化錯誤處理流程,下降運維成本。後續更是有dm-portal工具方便dba經過圖形化界面的方式進行選擇性導出和自動生成配置文件,雖然有一些小bug和不夠人性化的方面,但無傷大雅,惋惜的是這個項目最後諮詢官方得知被砍掉了,再也不進行維護。github

2、 緣由sql

我有幸從DM內測版本開始就接觸和使用這一工具,直至其最新版1.0.6,見證了DM功能不斷的完善,真切體會到了這一工具給咱們帶來的幫助,我認爲這是每個DBA和TiDB使用者都應該瞭解甚至熟練掌握的工具,由於大多數場景下,咱們使用TiDB並非全新的系統上去直接建庫建表,而是從MySQL遷移過來,先進行性能對比和測試,然後進行數據遷移的,所以熟練掌握DM工具可讓你的工做事半功倍。數據庫

3、架構架構

集羣配置mvc

集羣版本:v3.0.5
集羣配置:普通SSD磁盤,128G內存,40 核cpu
tidb21 TiDB/PD/pump/prometheus/grafana/CCS
tidb22 TiDB/PD/pump
tidb23 TiDB/PD/pump
tidb01 TiKV
tidb02 TiKV
tidb03 TiKV
tidb04 TiKV
tidb05 TiKV
tidb06 TiKV
tidb07 TiKV
tidb08 TiKV
tidb09 TiKV
tidb10 TiKV
tidb11 TiKV
tidb12 TiKV
tidb13 TiKV
tidb14 TiKV/DM-prometheus/DM-grafana/DMM
tidb15 TiKV/DMW1
tidb16 TiKV/DMW1

正常來講,官方建議抽出單獨的機器來部署DM,且推薦每一個節點上部署單個 DM-Worker 實例。除非機器擁有性能遠超 TiDB 軟件和硬件環境要求中推薦配置的 CPU 和內存,而且每一個節點配置 2 塊以上的硬盤或大於 2T 的 SSD,才推薦單個節點上部署不超過 2 個 DM-Worker 實例。而咱們的線上環境機器比較吃緊,因此一直以來都是和TiKV進行混部的,例如上述架構中,選取了tidb14,tidb15,tidb16進行dm相關的軟件部署。所幸運行起來效果還能夠,但有條件的建議你們仍是老老實實按照官方文檔,單獨部署。app

DM架構
TiDB DM踩坑實踐總結
DM架構如上圖所示,主要包括三個組件:DM-master,DM-worker 和 dmctl。
DM-master 負責管理和調度數據遷移任務的各項操做
DM-worker 負責執行具體的數據遷移任務
dmctl 是用來控制 DM 集羣的命令行工具
具體的功能本文再也不贅述,可參考官方文檔瞭解每個模塊的詳細功能運維

DM特性
Table routing 合併遷移
Block & allow table lists 白名單
Binlog event filter binlog級別過濾
Shard support 合庫合表curl

4、新特性

dm從內測版本開始,每個版本的迭代都修復和新加入了很多功能,這裏我單獨拎出來1.0.5這個版本,由於從這個版本開始,它支持了之前歷來沒有但又讓人早就期盼已久的功能:online ddl的支持。
衆所周知,MySQL在數據量大了後,沒有人會直接去對原表進行alter,大多數人都經過第三方工具pt-online-schema-change或者gh-ost來進行改表,以此削減改表期間對線上業務的影響。而早期的dm不支持該功能時,每次上游改完表後,因爲臨時表(_xxxx_new,_xxx_gho等)不在白名單裏,會直接致使下游tidb丟失該DDL,引起同步異常報警。固然,若是你是全庫同步,那天然不會有這個問題,但絕大多數場景下都是部分表導入到TiDB,用到了白名單功能的狀況下就會致使該問題出現。而1.0.5版本後,這便再也不是問題,雖然目前僅僅只能同時支持一種改表工具,但對比以前來講,無疑是我認爲最好的改進,還沒用的朋友們不妨試一試。

例如:
上游經過pt-online-schema-change工具爲表helei5新增一列
--alter="ADD column hl2 varchar(10) not null default '';" D=h_2,t=helei5
先看下沒有配置跳過的狀況
TiDB DM踩坑實踐總結
幾個關鍵的詞:

skip event 由於不在白名單中被跳過
skip event, need handled ddls is empty ,中間表由於被過濾掉在下游不存在,
因此提示is empty,也被跳過RENAME TABLE `h_2`.`helei5` TO `h_2`.`_helei5_old`",
"RENAME TABLE `h_2`.`_helei5_new` TO `h_2`.`helei5`
rename操做在上游爲了保證原子性是一條SQL實現表名互換的,
咱們能夠看到,好在拆分後也依舊是被跳過的,這是由於中間表不存在
rename的ddl裏部分表例如_helei5_new是空的,因此整個SQL不會被執行
"RENAME TABLE `h_2`.`helei5` TO `h_2`.`_helei5_old`的話被執行了是咱們不但願看到的

此時task狀態依舊是running,但下游已經沒有新增的列

{
            "taskName": "task_4369",
            "taskStatus": "Running",
            "workers": [
                「192.168.1.248:8262"
            ]

此時插入包含新列h2的數據
mysql> insert into helei5 values(14,'cccc','pt alter');

這個時候dm就會報錯

{
            "taskName": "task_4369",
            "taskStatus": "Error - Some error occurred in subtask. Please run `query-status task_4369` to get more details.",
            "workers": [
                「192.168.1.248:8262"
            ]

報錯信息是:
msg": "[code=36027:class=sync-unit:scope=internal:level=high] current pos (4369-binlog|000001.000021, 62771055): gen insert sqls failed, schema: h_2, table: helei5: Column count doesn't match value count: 2 (columns) vs 3 (values)

點位:
sync": {
                        "totalEvents": "3",
                        "totalTps": "0",
                        "recentTps": "0",
                        "masterBinlog": "(4369-binlog.000021, 62774081)",
                        "masterBinlogGtid": "1c3add9b-7c26-11e7-81bf-70e28411103e:1-910975,1d1872fd-7c26-11e7-81bf-70e284110e52:1-3,200ccab3-f941-11e8-b6de-6c92bf96384c:1-800846",
                        "syncerBinlog": "(4369-binlog|000001.000021, 62765733)",

由於少列,因此報錯,咱們在下游添加列,而後跳過

mysql> alter table helei5 add column h2 varchar(10) not null default '';
跳過語句是:
» sql-skip --worker=192.168.1.248:8262 --binlog-pos=4369-binlog|000001.000021:62765733 task_4369
{
    "result": true,
    "msg": "",
    "workers": [
        {
            "result": true,
            "worker": "",
            "msg": ""
        }
    ]
}

dm-worker的日誌有以下內容:

[2020/05/14 15:48:05.883 +08:00] [INFO] [operator.go:136] ["set a new operator"] [task=task_4369] [unit="binlog replication"] ["new operator"="uuid: b52784e4-e804-46f5-974c-ca811a34dc30, pos: (4369-binlog|000001.000021, 62765733), op: SKIP, args: "]

執行恢復任務

» resume-task task_4369  

        {
            "taskName": "task_4369",
            "taskStatus": "Running",
            "workers": [
                「192.168.1.248:8262"

在添加online-ddl-scheme: "pt"參數後,下游成功讀取到pt-online-schama-change加的新列:
TiDB DM踩坑實踐總結

gh-ost工具同理:

幾個關鍵詞:
ghc表的建立DM是忽略的:
prepare to handle ddls
skip event, need handled ddls is empty
gho表的建立和新DDL也是忽略的,而是把該 DDL 記錄到 dm_meta.{task_name}\_onlineddl 以及內存中:
prepare to handle ddls
skip event, need handled ddls is empty
del表的建立也是忽略的:
rename /* gh-ost */ table `h_2`.`helei5` to `h_2`.`_helei5_del`, `h_2`.`_helei5_gho` to `h_2`.`helei5`
不執行 rename to _helei5_del。當要執行 rename ghost_table to origin table 的時候,並不執行 rename 語句,而是把記錄在內存中的 DDL 讀取出來,而後把 ghost_table、ghost_schema 替換爲 origin_table 以及對應的 schema,再執行替換後的 DDL。
操做完日誌會有:
finish online ddl and clear online ddl metadata in normal mode

在添加online-ddl-scheme: "gh-ost"的參數後,下游也讀取到了加的列
TiDB DM踩坑實踐總結

5、1062的踩坑

在早期,咱們有一個業務經過DM同步到TiDB,但每過幾個小時後,同步老是中斷,而每次咱們人工resume task又能恢復,諮詢後得知resume操做後,dm內部前幾分鐘是debug模式,執行的replace。
當時的報錯內容以下:

>> query-status task_3306
...
...
 "msg": "[code=10006:class=database:scope=not-set:level=high] execute statement failed: commit: Error 1062: Duplicate entry '21277ed5f5e7c3b646a5229269d54d3a7fccc08bf34c8f2113fdd4df62f4a229' for key 'clientid'\ngithub.com/pingcap/dm/pkg/terror.(*Error).Delegate\n
>>query-error task_3306
"errorSQL": "[tp: insert, sql: INSERT INTO `360sudi`.`client` (`id`,`clientid`,`toid`,`updatetime`) VALUES (?,?,?,?);, args: [4102315138 62ba2a78af090ab1337c6b62f8dedfc8b6338007cdeb5a7ea4e7f4b4c23e3e0c 3250350869 2019-11-21 19:54:56], key: 4102312246, ddls: []

用自增id的主鍵查:

[helei@db01 ~]$ curl http://192.168.1.1:10080/mvcc/key/360/client/4102315138
{
 "key": "7480000000000011945F7280000000F4845C82",
 "region_id": 2278436,
 "value": {
  "info": {
   "writes": [
    {
     "type": 3,
     "start_ts": 412703076417274370,
     "commit_ts": 412703076417274370
    }
   ]
  }
 }
}

根據查詢出來的 commit-ts 使用 pd-ctl tso 命令看下在下游已經存在的記錄提交的時間

[root@tidb helei]# /data1/tidb-ansible-3.0.5/resources/bin/pd-ctl -i -u http://192.168.1.2:2379     
» tso
Usage: tso <timestamp>
» tso 412703076417274327
system:  2019-11-21 19:54:57.124 +0800 CST
logic:  471
» tso 412702903507091560
system:  2019-11-21 19:43:57.524 +0800 CST
logic:  104
»

查找 dm-worker 日誌中跟這個記錄相關的內容

-binlog.000020, 185499141), relay-binlog-gtid = "]
[2019/11/21 19:54:47.710 +08:00] [INFO] [syncer.go:2004] ["binlog replication progress"] [task=task_3306] [unit="binlog replication"] ["total binlog size"=378940822] ["last binlog size"=378533105] ["cost time"=30] [bytes/Second=13590] ["unsynced binlog size"=0] ["estimate time to catch up"=0]
[2019/11/21 19:54:47.710 +08:00] [INFO] [syncer.go:2029] ["binlog replication status"] [task=task_3306] [unit="binlog replication"] [total_events=1528442] [total_tps=1455] [tps=40] [master_position="(3306-binlog.000020, 185616633)"] [master_gtid=] [checkpoint="(3306-binlog|000001.000020, 185616633)(flushed (3306-binlog|000001.000020, 185484711))"]
[2019/11/21 19:54:57.157 +08:00] [ERROR] [db.go:269] ["execute statements failed after retry"] [task=task_3306] [unit="binlog replication"] [queries="[INSERT INTO `360sudi`.`client` (`id`,`clientid`,`toid`,`updatetime`) VALUES (?,?,?,?);]"] [arguments="[[4102315138 62ba2a78af090ab1337c6b62f8dedfc8b6338007cdeb5a7ea4e7f4b4c23e3e0c 3250350869 2019-11-21 19:54:56]]"] [error="[code=10006:class=database:scope=not-set:level=high] execute statement failed: commit: Error 1062: Duplicate entry '62ba2a78af090ab1337c6b62f8dedfc8b6338007cdeb5a7ea4e7f4b4c23e3e0c' for key 'clientid'"]

比較下第二個步驟查詢出來的時間和第三個步驟查詢出來的時間
第二個步驟 2019-11-21 19:54:57.124 +0800 CST
第三個步驟 2019/11/21 19:54:57.157 +08:00
第二個步驟2019-11-21 19:43:57.524的時間,在第三個步的worker日誌裏未找到相關

咱們嘗試過:

1.將dm下游配置爲單一tidb而非tidb的lvs,防止多個ip寫入ntp引發毫秒級的偏差(無果)
2.task文件針對syncer的worker進行限制,只讓一個syncer進行同步(無果)
3.業務變動爲replace into,開始測試
改syncer worker count的時候,光rolling_update是沒用的,須要dm-ctl去stop/start task才能夠生效

能夠看到,15:25起,qps在syncer worker count配置爲16後瞬間從256漲到4k
TiDB DM踩坑實踐總結
限制worker,庫裏也有多個而非一個進程
TiDB DM踩坑實踐總結
而單個進程依然會報錯1062不說,還會致使延遲不斷增長,以後咱們又調整會16後,能看到快速追上上游主庫日誌
TiDB DM踩坑實踐總結
最終咱們是經過業務更改replace into解決該問題

6、DM大批量導入調參

集羣穩定運行旗艦,有新數據要經過DM灌入,此時會影響已有集羣的穩定性
以下圖所示,能看到DM導入期間集羣響應出現延遲
TiDB DM踩坑實踐總結

咱們經過以下參數從原值調到-新值規避了這一問題,但每一個集羣場景和配置徹底不一樣,適度謹慎調整,調整前應瞭解每個參數的含義,以下僅作參考

raftstore:
apply-pool-size: 3-4
store-pool-size: 3-4

storage:
scheduler-worker-pool-size: 4-6

server:
grpc-concurrency: 4-6

rocksdb:
max-background-jobs: 8-10
max-sub-compactions: 1-2

7、限制

版本限制:

  • 數據庫版本
    • 5.5 < MySQL 版本 < 8.0
    • MariaDB 版本 >= 10.1.2
  • 僅支持 TiDB parser 支持的 DDL 語法
  • 上下游 sql_model 檢查
  • 上游開啓 binlog,且 binlog_format=ROW

DM不支持的類型:
1)一次刪除多個分區的操做則會報錯:
alter table dsp_group_media_report drop partition p202006 ,p202007 ;

2)drop含有索引的列操做會報錯
Alter table dsp_group drop column test_column;

DM-portal限制:
●在早期尚未dm-portal自動化生成task時,咱們都是自行編寫DM的task同步文件
●後來有了dm-portal自動化生成工具,只要圖形頁面點點點就能夠了
TiDB DM踩坑實踐總結
但該工具目前有一個問題是,沒有全庫正則匹配,幾遍你只勾選一個庫,他底層是默認把每張表都給你配置一遍。這就會出現當上層MySQL新建立某張表的時候,下游會被忽略掉,例如當你使用改表工具gh-ost或者pt-online-schema-change,你的臨時表都會被當作爲不在白名單內而被忽略,這個問題使用者須要注意。咱們也已經反饋給了官方。且如文章第四節所示,已於1.0.5版本修復。

DM-worker清理配置:

[purge]
interval = 3600
expires = 7
remain-space = 15

關於relay-log,默認是不清理的,就和mysql的expire_logs_days同樣,這塊能夠經過dm-worker的配置文件來進行配置,例如將expires配置爲7,表明7天后刪除:

#默認expires=0,即沒有過時時間,而remain-space=15意思是當磁盤只剩於15G的時候開始嘗試清理,這種狀況咱們極少會碰到,所以這個清理方式其實基本上是用不到的。因此建議有須要刪除過時relay-log的小夥伴,直接配置expires保留天數就能夠了。

DM導入完成後,應該提供是否在完成後自動刪除全備文件的選項,能夠默認不刪,由使用者決定是否刪除。
從使用者角度來講,全量備份目錄不管是全量一次性導入仍是all增量同步,後續都不會再使用到。若是dm-worker和tikv混部,會致使全備文件佔據大量磁盤空間,引發tikv region評分出現異常,致使性能降低,這一點若是有相同的架構的朋友們需得注意。

默認調度策略是當磁盤剩餘的有效空間不足 40% ,處於中間態時則同時考慮數據量和剩餘空間兩個因素作加權和看成得分,當得分出現比較大的差別時,就會開始調度。

因此DM導入完成後,要記得刪除全量備份,就是dumped_data.task_xxx文件夾,這個全量備份通常都會比較大,並且默認是不刪除的,也沒有配置項。若是dm-worker和tikv混部,就會出現某個tikv節點磁盤已使用率高於其餘,這時pd的store region score就會相比其餘節點出現異常。引發性能抖動和duration升高

8、總結和感慨

零零散散,大大小小的分享也作了不少了,從小白用戶第一次在2019年7月接觸TiDB,到入選核心成員組,到MVA,到DEVCON 2020做爲嘉賓宣講360在TiDB的分享,再到後續獲TUG最具備影響力內容獎章,筆者一直都是本着分享才能讓人進步的態度,毫無保留去分享技術乾貨。由於我真真切切的感覺到了TiDB產品自己,以及TiDB社區在不斷的作大,作強。就拿我司來講,360集團目前已經8個業務線在使用,4套集羣,總數據量接近190TB,穩定流暢運行。目前12月份還接了一個大部門的80人TiDB內部培訓,從我本身來講,我要感謝TiDB,感謝社區,我分享的同時,也有不少大牛幫助我改正文中的錯誤,讓我本身也有了進一步的提高。同時我還認識了不少的不少志同道合的朋友,有美團,58同城,新東方,伴魚,汽車之家,京東數科等等,我願意進一步去毫無保留的分享,來認識更多的朋友。

相關文章
相關標籤/搜索