作者:張學程
本文為 DM 源碼閱讀系列文章的第二篇,第一篇文章 簡單介紹了 DM 源碼閱讀的目的和規劃,以及 DM 的源碼結構以及工具鏈。從本篇文章開始,我們會正式開始閱讀 DM 的源碼。
本篇文章主要介紹 DM 的整體架構,包括 DM 有哪些組件、各組件分別實現什麼功能、組件之間交互的數據模型和 RPC 實現。
通過上面的 DM 架構圖,我們可以看出,除上下游資料庫及 Prometheus 監控組件外,DM 自身有 DM-master、DM-worker 及 dmctl 這 3 個組件。其中,DM-master 負責管理和調度數據同步任務的各項操作,DM-worker 負責執行具體的數據同步任務,dmctl 提供用於管理 DM 集群與數據同步任務的各項命令。
DM-master 的入口代碼在 cmd/dm-master/main.go,其中主要操作包括:
cmd/dm-master/main.go
cfg.Parse
log.SetLevelByString
signal.Notify
server.Start
在上面的操作中,可以看出其中最關鍵的是步驟 4,其對應的實現代碼在 dm/master/server.go 中,其核心為 Server 這個 struct,其中的主要 fields 包括:
dm/master/server.go
Server
rootLis, svr
workerClients
taskWorkers
lockKeeper
sqlOperatorHolder
在本篇文章中,我們暫時不會關注 lockKeeper 與 sqlOperatorHolder,其具體的功能與代碼實現會在後續相關文章中進行介紹。
在 DM-master Server 的入口方法 Start 中:
Start
net.Listen
rootLis
DeployMap
pb.RegisterMasterServer
svr
m.Serve
DM-master 提供的 RPC 服務包括 DM 集群管理、同步任務管理等,對應的 service 以 Protocol Buffers 格式定義在 dm/proto/dmmaster.proto 中,對應的 generated 代碼在 dm/pb/dmmaster.pb.go 中。各 service 的具體實現在 dm/master/server.go 中(*Server)。
dm/proto/dmmaster.proto
dm/pb/dmmaster.pb.go
*Server
DM-worker 的結構與 DM-master 類似,其入口代碼在 cmd/dm-worker/main.go 中。各 RPC services 的 Protocol Buffers 格式定義在 dm/proto/dmworker.proto 中,對應的 generated 代碼在 dm/pb/dmworker.pb.go 中,對應的實現代碼在 dm/worker/server.go 中(*Server)。DM-worker 的啟動流程與 DM-master 類似,在此不再額外說明。
cmd/dm-worker/main.go
dm/proto/dmworker.proto
dm/pb/dmworker.pb.go
dm/worker/server.go
Server 這個 struct 的主要 fields 除用於處理 RPC 的 rootLis 與 svr 外,另一個是用於管理同步任務與 relay log 的 worker(相關代碼在 dm/worker/worker.go 中)。
worker
dm/worker/worker.go
在 Worker 這個 struct 中,主要 fields 包括:
Worker
subTasks
relayHolder
relayPurger
數據同步子任務管理的代碼實現主要在 dm/worker/subtask.go 中, relay 處理單元管理的代碼實現主要在 dm/worker/relay.go 中,對 relay log 進行 purge 操作的代碼實現主要在 relay/purger pkg 中。在本篇文章中,我們暫時只關注 DM 架構相關的實現,上述各功能的具體實現將在後續的相關文章中展開介紹。
dm/worker/subtask.go
dm/worker/relay.go
relay/purger
Worker 的入口方法為 Start,其中的主要操作包括:
w.relayHolder.Start
w.relayPurger.Start
其他的操作主要還包括處理 Server 轉發而來的同步任務管理、relay 處理單元管理、狀態信息查詢等。
dmctl 的入口代碼在 cmd/dm-ctl/main.go,其操作除參數解析與 signal 處理外,主要為調用 loop 進入命令處理循環、等待用戶輸入操作命令。
cmd/dm-ctl/main.go
loop
在 loop 中,我們藉助 chzyer/readline 提供命令行交互環境,讀取用戶輸入的命令並輸出命令執行結果。一個命令的處理流程為:
l.Readline
ctl.Start
dmctl 的具體命令處理實現在 dm/ctl pkg 中,入口為 dm/ctl/ctl.go 中的 Start 方法,命令的分發與參數解析藉助於 spf13/cobra。命令的具體功能實現在相應的子 pkg 中:
dm/ctl
dm/ctl/ctl.go
master
common
每個 dmctl 命令,其主要對應的實現包括 3 個部分:
New***Cmd
cobra.Command
rootCmd.AddCommand
***Func
讓我們用一個啟動數據同步任務的操作示例來說明 DM 中的組件交互與 RPC 調用流程。
dm/ctl/master/start_task.go
startTaskFunc
cli.StartTask
Server.StartTask
Server.Start
cli.StartSubTask
Server.StartSubTask
Worker.StartSubTask
common.PrettyPrintResponse
在本篇文章中,我們主要介紹了 DM 的各個組件的入口函數,最後以 dmctl 的 start-task 為例介紹了交互的調用流程細節。下一篇文章我們會開始介紹 DM-worker 組件內各數據同步處理單元(relay-unit, dump-unit, load-unit, sync-unit)的設計原理與具體實現。
更多閱讀: