DM 原始碼閱讀系列文章(一)序

PingCAP發表於2019-03-20

作者:楊非

前言

TiDB-DM 是由 PingCAP 開發的一體化資料同步任務管理平臺,支援從 MySQL 或 MariaDB 到 TiDB 的全量資料遷移和增量資料同步,在 TiDB DevCon 2019 正式開源。作為一款連線 MySQL/MariaDB 生態和 TiDB 生態的中臺型別產品,DM 獲得了廣泛的關注,很多公司、開發者和社群的夥伴已經在使用 DM 來進行資料遷移和管理。隨著大家使用的廣泛和深入,遇到了不少由於對 DM 原理不理解而錯誤使用的情況,也發現了一些 DM 支援並不完善的場景和很多可以改進的地方。

在這樣的背景下,我們希望開展 DM 原始碼閱讀分享活動,通過對 DM 程式碼的分析和設計原理的解讀,幫助大家理解 DM 的實現原理,和大家進行更深入的交流,也有助於我們和社群共同進行 DM 的設計、開發和測試。

背景知識

本系列文章會聚焦 DM 自身,讀者需要有一些基本的知識,包括但不限於:

  • Go 語言,DM 由 Go 語言實現,有一定的 Go 語言基礎有助於快速理解程式碼。

  • 資料庫基礎知識,包括 MySQL、TiDB 的功能、配置和使用等;知道基本的 DDL、DML 語句和事務的基本常識;MySQL 資料備份、主從同步的原理等。

  • 基本的後端服務知識,比如後臺服務程式管理、RPC 工作原理等。

總體而言,讀者需要有一定 MySQL/TiDB 的使用經驗,瞭解 MySQL 資料備份和主從同步的原理,以及可以讀懂 Go 語言程式。在閱讀 DM 原始碼之前,可以先從閱讀《TiDB-DM 架構設計與實現原理》入手,並且參考 使用文件 在本地搭建一個 DM 的測試環境,從基礎原理和使用對 DM 有一個初步的認識,然後再進一步分析原始碼,深入理解程式碼的設計和實現。

內容概要

原始碼閱讀系列將會從兩條線進行展開,一條是圍繞 DM 的系統架構和重要模組進行分析,另一條線圍繞 DM 內部的同步機制展開分析。原始碼閱讀不僅是對程式碼實現的分析,更重要的是深入的分析背後的設計思想,原始碼閱讀和原理分析的覆蓋範圍包括但不限於以下列出的內容(因為目前 DM 仍處於快速迭代的階段,會有新的功能和模組產生,部分模組在未來也會進行優化和重構,後續原始碼閱讀的內容會隨著 DM 的功能演進做適當的調整):

  • 整體架構介紹,包括 DM 有哪些模組,分別實現什麼功能,模組之間互動的資料模型和 RPC 實現。

  • DM-worker 內部元件設計原理(relay-unit, dump-unit, load-unit, sync-unit)和資料同步的併發模型設計與實現。

  • 基於 binlog 的資料同步模型設計和實現。

  • relay log 的原理和實現。

  • 定製化資料同步功能的實現原理(包括庫表路由,庫表黑白名單,binlog event 過濾,列值轉換)。

  • DM 如何支援上游 online DDL 工具(pt-osc, gh-ost)的 DDL 同步場景。

  • sharding DDL 處理的具體實現。

  • checkpoint 的設計原理和實現,深入介紹 DM 如何在各類異常情況下保證上下游資料同步的一致性。

  • DM 測試的架構和實現。

程式碼簡介

DM 原始碼完全託管在 GitHub 上,從 專案主頁 可以看到所有資訊,整個專案使用 Go 語言開發,按照功能劃分了很多 package,下表列出了 DM 每個 package 的基本功能:

Package Introduction
checker 同步任務上下游資料庫配置、許可權前置檢查模組
cmd/dm-ctl, cmd/dm-master, cmd/dm-worker dmctl, DM-master, DM-worker 的 main 檔案所在模組
dm/config 同步任務配置、子任務配置、前置檢查配置定義模組
dm/ctl dmctl 所有 RPC 呼叫實現的模組
dm/master DM-master 的核心實現,包含了 DM-master 後臺服務,對 dmctl 到 DM-master 的 RPC 呼叫的處理邏輯,對 DM-worker 的管理,對 sharding DDL 進行協調排程等功能
dm/pb, dm/proto dm/proto 定義了 DM-master 和 DM-worker 相關互動的 protobuf 協議,dm/pb 是對應的生成程式碼
dm/unit 定義了子任務執行的邏輯單元(包括 dump unit, load unit, sync unit, relay unit)介面,在每個不同邏輯單元對應的 package 內都有對應的 介面實現
dm/worker DM-worker 的核心實現,實現 DM-worker 後臺服務,管理維護每個任務的 relay 邏輯單元,管理、排程每個子任務的邏輯單元
loader 子任務 load 邏輯單元的實現,用於全量資料的匯入
mydumper 子任務 dump 邏輯單元的實現,用於全量資料的匯出
pkg 包含了一些基礎功能的實現,例如 gtid 操作、SQL parser 封裝、binlog 檔案流讀寫封裝等
relay 處理 relay log 同步的核心模組
syncer 子任務 sync 邏輯單元的實現,用於增量資料的同步

對於理解程式碼最直接的手段就是從 DM-server, DM-worker 和 dmctl 三個 binary 對應的 main 檔案入手,看 DM-worker, DM-master 是如何啟動,DM-worker 如何管理一個上游例項和同步任務;如何從 dmctl 開始同步子任務;然後看一個同步子任務從全量狀態,到增量同步狀態,binlog 如何處理、sql 任務如何分發等。通過這樣一個流程對 DM 的整體架構就會有全面的理解。進一步就可以針對每個使用細節去了解 DM 背後的設計邏輯和程式碼實現,可以從具體每個 package 入手,也可以從感興趣的功能入手。

實際上 DM 程式碼中使用了很多優秀的第三方開原始碼,包括但不僅限於:

  • 藉助 grpc 實現各元件之間的 RPC 通訊

  • 藉助 pingcap/parser 進行 DDL 的語法解析和語句還原

  • 藉助 pingcap/tidb-tools 提供的工具實現複雜的資料同步定製

  • 藉助 go-mysql 解析 MySQL/MariaDB binlog 等

在原始碼閱讀過程中對於比較重要的、與實現原理有很高相關度的第三方模組,我們會進行相應的擴充套件閱讀。

工具鏈

工欲善其事,必先利其器,在閱讀 DM 原始碼之前,我們先來介紹 DM 專案使用到的一些外部工具,這些工具通常用於 DM 的構建、部署、執行和測試,在逐步使用 DM,閱讀程式碼、理解原理的過程中都會使用到這些工具。

  • golang 工具鏈:構建 DM 需要 go >= 1.11.4,目前支援 Linux 和 MacOS 環境。

  • gogoprotobuf:用於從 proto 描述檔案生成 protobuf 程式碼,DM 程式碼倉庫的 generate-dm.sh 檔案封裝了自動生成 DM 內部 protobuf 程式碼的指令碼。

  • Ansible:DM 封裝了 DM-Ansible 指令碼用於 DM 叢集的自動化部署,部署流程可以參考 使用 ansible 部署 DM

  • pt-osc, gh-ost:用於上游 MySQL 進行 online-ddl 的同步場景。

  • mydumper:DM 的全量資料 dump 階段直接使用 mydumper 的 binary。

  • MySQL, TiDB, sync_diff_inspector:這些主要用於單元測試和整合測試,可以參考 tests#preparations 這部分描述。

小結

本篇文章主要介紹了 DM 原始碼閱讀的目的和原始碼閱讀的規劃,簡單介紹了 DM 的原始碼結構和工具鏈。下一篇文章我們會從 DM 的整體架構入手,詳細分析 DM-master、DM-worker 和 dmctl 三個元件服務邏輯的實現和功能抽象,RPC 資料模型和互動介面。更多的程式碼閱讀內容會在後面的章節中逐步展開,敬請期待。

DM 原始碼閱讀系列文章(一)序

相關文章