背景
使用者在做技術選型的過程中,總是會對一些資料指標比較關心,特別是在和競品相比較的時候,更加需要一些有說服力的資料。基於MySQL開發的專案在遷移到TiDB的時候,使用DM同步資料是必不可少的一個環節,我在最近的一次POC中就碰到了這樣一個需求,需要評估一個具體的延時時間參考值,因為使用者在遷移前期的過渡階段是把TiDB作為MySQL的從庫,有些場景對這個延時很敏感,如果延時太大會直接影響業務。
由於DM並不能直接看到整個鏈路的延時時間,所以我們必須另闢蹊徑找一些辦法來實現,以下是我實踐過的幾種辦法,也希望能拋磚引玉,帶出其他大佬給社群帶來更好的方案。
我的思路比較簡單,就是分別根據上下游事務的某個時間點來計算時間差,這個時間差應該要精確到毫秒級,可以從三個方向入手:
-
Binlog Position
-
TiDB General log
-
SQL自動記錄時間
接下來就分別看一下如何實現。
基於Binlog Position
DM增量同步是基於訂閱MySQL Binlog來實現的,所以首先考慮的辦法就是通過Binlog Position來定位某一個事務,只要分別找到同一個Position在Binlog和DM-Worker Log中記錄的時間,就可以大致計算出這個時間差。
我使用如下一張測試表來演示這個過程:
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`mysql_created` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
在DM Task完全啟動成功之後,我們往MySQL裡的table1插入一條資料:
insert into table1 values(1,null);
插入成功後我們找到這個事務第一個events的position,這個示例中是1422:
接下來去binlog檔案中解析出這段範圍內的事務內容,裡面有我們需要的時間:
注意看裡面的TIMESTAMP內容,意思是事務開始時的時間是21:45:38:572
,原始內容精確到了微秒級別,我們這裡只取毫秒來計算。
然後拿事務開始的position去dm-worker的日誌中搜尋相應的內容,當binlog被處理完成後會輸出flushed checkpoint
字樣的內容,我們根據關鍵字去日誌檔案中搜尋:
從這裡可以得到1422被寫入完成的時間是21:45:38.603
,前後相減一下大概時間差是31ms。
要注意的是,我理解整個鏈路的過程應該是:mysql(事務開始)->binlog->dm-worker->tidb->dm-worker,相當於TiDB寫完後多了一個通知dm-worker的過程。
基於TiDB General log
第二種與前一種類似,我希望能定位到事務實際被TiDB執行完成的時間,這時候可以藉助TiDB的GENERAL_LOG
功能,用事務號(TSO)去定位。
我們首先開啟TiDB例項的General Log開關:
mysql> set tidb_general_log=1;
Query OK, 0 rows affected (0.08 sec)
前半部分和之前一樣,還是去binlog檔案中找到MySQL事務開始時間戳,這裡是22:08:55:419
:
然後開啟TiBD的Dashboard頁面,用如下關鍵字搜尋TiDB節點的日誌:
雖然這個頁面能看到日誌的記錄時間,但是存在兩個問題,一個是不能精確到毫秒,第二個這並不是事務的提交時間,我們需要進一步根據事務號(TSO)去原始檔案中搜尋準確時間。
這裡的commit時間是22:08:55.434
,前後相減的時間差大概15ms。
這裡也可以一步到位直接去原始log檔案去搜,省去Dashboard查詢TSO的過程。
這個鏈路過程是:mysql(事務開始)->binlog->dm-worker->tidb(事務提交)。
基於SQL自動記錄時間
前面兩種方法都要各種搜尋日誌稍微有點麻煩,本著將偷懶進行到底的精神,能不能直觀地看出上下游各自的時間?最理想的情況是:一句SQL就能查出來。
從前面的測試中可以發現,時間欄位設定當前時間為預設值只對上游生效,同步到TiDB的時候是把實際值傳過去了,並不是根據欄位定義生成新值。因此,我希望資料到TiBD的時候也能生成當前時間寫入某個欄位,但是這個欄位不能在MySQL中存在,也就是說上下游資料結構不一樣。
那DM可以支援這種同步嗎?必然是可以的。
關於上下游異構同步官網文件有詳細介紹,大家可以參考文件:https://docs.pingcap.com/zh/tidb-data-migration/stable/manage-schema。
我們要使用的帶預設值異構同步其實更簡單,DM不用做任何操作就能支援。
我們在前面的DM Task完全不動的情況下,只給下游TiDB的table1增加一個欄位:
alter table table1 add COLUMN tidb_created timestamp(3) NOT NULL DEFAULT current_timestamp(3);
然後往上游插入一條測試資料:
insert into table1 values(3,null);
插入成功後去TiDB中查詢這個表,兩個建立時間都能看到了:
是不是非常簡單。
這個鏈路的過程是:mysql(事務開始)->binlog->dm-worker->tidb(事務開始)。
總結
以上3種方式從不同維度計算了一次資料同步的延時情況,這個資料具有一定的參考性。但是使用的過程中要注意每一種的區別,選擇你最適合最關心的指標來作為參考。
本文如有不正確的地方歡迎指出,當然了,也歡迎大家推薦更好的方案,一起交流~