天天看點

TiDB PD 元件代碼閱讀

作者:孫曉光

PD (Placement Driver) 是 TiDB 的大腦,它負責全局中繼資料的存儲以及 TiKV 元件的負載均衡排程。

基本名詞解釋:

  • Store: 一個 TiKV 存儲執行個體在 PD 中對應一個 Store,PD 為一個 Store 維護了下面的元資訊

{

“store”: {

“id”: xx,

“address”: “xx.xx.xx.xx:xxxx”,

“labels”: [

​ { "key": "host", "value": "xxx.xxx.xxx" }, { "key": "zone", "value": "xx" } ​

],

“version”: “2.1.8”,

“state_name”: “Up”

},

“status”: {

“capacity”: “3.6 TiB”,

“available”: “2.3 TiB”,

“leader_count”: 4898,

“leader_weight”: 1,

“leader_score”: 2215540,

“leader_size”: 2215540,

“region_count”: 14750,

“region_weight”: 1,

“region_score”: 6665256,

“region_size”: 6665256,

“start_ts”: “2019-09-27T23:51:53+08:00”,

“last_heartbeat_ts”: “2019-10-10T14:09:03.568260056+08:00”,

“uptime”: “302h17m10.568260056s”

}

}

  • Region: 負載均衡的最小單元。TiKV 中的全量資料是以有序的方式存儲的,PD 根據資料的尺寸将全量資料分割成一系列的 Region,每一個 Region 承載全量資料中一段較小範圍的資料。PD 為每一個 Region 維護了下面的元資訊

{

“id”: 10001,

“start_key”: “xxx”,

“end_key”: “yyy”,

“epoch”: {

“conf_ver”: 50,

“version”: 268

},

“peers”: [

{

​ "id": 7820688, "store_id": 7583502 ​

},

{

​ "id": 9147810, "store_id": 7586672 ​

},

{

​ "id": 9186477, "store_id": 7584594 ​

}

],

“leader”: {

“id”: 7820688,

“store_id”: 7583502

},

“written_bytes”: 15639,

“read_bytes”: 236,

“approximate_size”: 515,

“approximate_keys”: 4747086

}

  • Peer: Store 在 Region 上的一次具體綁定
  • Scheduler: 排程器,目前 master 版本上已有的 scheduler 種類如下
  • adjacent-region: 将連續的 region 的 leader 分散到不同的 store 上
  • balance-leader: 将 leader 在所有的 store 上均勻的分散開
  • balance-region: 将 region 在所有的 store 上均勻的分散開
  • evict-leader: 将指定 store 上的 leader 全部驅逐走
  • grant-leader: 将指定 store 負責的所有 region 的 leader 都收集到指定的 store 上
  • balance-hot-region: 将熱點 region 在所有的 store 上均勻的分散開
  • random-merge: 随機挑選兩個連續的 region 進行合并
  • scatter-range: 将指定 key 範圍内的 region 在 store 見均勻的分散開
  • shuffle-hot-region: 将熱點 region 的 leader 排程到一個随機 store 上(測試用)
  • shuffle-leader: 将 leader 随機的 shuffle 到 store 上
  • shuffle-region: 将 region 随機的 shuffle 到 store 上
  • Operator: 排程器實際發出的排程任務,目前 master 版本上已有的 operator 類型如下
  • TransferLeader
  • AddPeer
  • AddLearner
  • PromoteLearner
  • RemovePeer
  • MergeRegion
  • SplitRegion
  • AddLightPeer
  • TSO: 時間戳配置設定器
  • Label: 節點标簽,用作排程政策的輸入資料
  • Replica: Region 資料副本
  • Leader: 目前負責讀寫操作的副本

主體代碼目錄結構:

  • client: pd go 語言 client,主要接口如下

// Client is a PD (Placement Driver) client.

// It should not be used after calling Close().

type Client interface {

// GetClusterID gets the cluster ID from PD.

GetClusterID(ctx context.Context) uint64

// GetTS gets a timestamp from PD.

GetTS(ctx context.Context) (int64, int64, error)

// GetTSAsync gets a timestamp from PD, without block the caller.

GetTSAsync(ctx context.Context) TSFuture

// GetRegion gets a region and its leader Peer from PD by key.

// The region may expire after split. Caller is responsible for caching and

// taking care of region change.

// Also it may return nil if PD finds no Region for the key temporarily,

// client should retry later.

GetRegion(ctx context.Context, key []byte) (*metapb.Region, *metapb.Peer, error)

// GetPrevRegion gets the previous region and its leader Peer of the region where the key is located.

GetPrevRegion(ctx context.Context, key []byte) (*metapb.Region, *metapb.Peer, error)

// GetRegionByID gets a region and its leader Peer from PD by id.

GetRegionByID(ctx context.Context, regionID uint64) (*metapb.Region, *metapb.Peer, error)

// ScanRegion gets a list of regions, starts from the region that contains key.

// Limit limits the maximum number of regions returned.

// If a region has no leader, corresponding leader will be placed by a peer

// with empty value (PeerID is 0).

ScanRegions(ctx context.Context, key []byte, limit int) ([]*metapb.Region, []*metapb.Peer, error)

// GetStore gets a store from PD by store id.

// The store may expire later. Caller is responsible for caching and taking care

// of store change.

GetStore(ctx context.Context, storeID uint64) (*metapb.Store, error)

// GetAllStores gets all stores from pd.

// The store may expire later. Caller is responsible for caching and taking care

// of store change.

GetAllStores(ctx context.Context, opts …GetStoreOption) ([]*metapb.Store, error)

// Update GC safe point. TiKV will check it and do GC themselves if necessary.

// If the given safePoint is less than the current one, it will not be updated.

// Returns the new safePoint after updating.

UpdateGCSafePoint(ctx context.Context, safePoint uint64) (uint64, error)

// ScatterRegion scatters the specified region. Should use it for a batch of regions,

// and the distribution of these regions will be dispersed.

ScatterRegion(ctx context.Context, regionID uint64) error

// GetOperator gets the status of operator of the specified region.

GetOperator(ctx context.Context, regionID uint64) (*pdpb.GetOperatorResponse, error)

// Close closes the client.

Close()

}

  • pkg: utility 功能
  • server: pd server 的主體代碼
  • api: PD 的 Restful API 相關邏輯
  • cache: 緩存資料結構,目前用于管理熱點統計資訊
  • core: 核心業務邏輯以及叢集中繼資料的持久化
  • namespace: namespace 功能目前已不推薦使用
  • placement: 副本放置政策腳本語言功能
  • region_syncer: 在 PD 副本間同步 region 中繼資料
  • schedule: operator 相關代碼,各種類型的排程任務實作在 operator*.go 中,輔助實作排程任務的通用邏輯在其他檔案中
  • scheduler: 排程器相關代碼,多數排程器是以一個檔案一個實作的方式組織的
  • statistics: 維護 region 和 store 的統計資訊
  • table: TiDB key 編碼相關代碼,用于實作 namespace 功能(deprecated,不推薦使用)

排程器相關代碼

  • interface: server/schedule/scheduler.go

// Scheduler is an interface to schedule resources.

type Scheduler interface {

GetName() string

// GetType should in accordance with the name passing to schedule.RegisterScheduler()

GetType() string

GetMinInterval() time.Duration

GetNextInterval(interval time.Duration) time.Duration

Prepare(cluster Cluster) error

Cleanup(cluster Cluster)

Schedule(cluster Cluster) []*Operator

  • adjacent-region: server/scheduler/adjacent_region.go
  • 從上次掃描結束的 key 開始掃描最多 1000 個 region
  • 從掃描到的 region 中查找同一 leader 負責連續多個 region 的情況作為候選緩沖起來
  • 對候選區間進行計算生成最終的排程任務
  • balance-leader: server/scheduler/balance_leader.go
  • 在所有 store 中挑選出目前 leader score 最高和最低的兩個分别作為源和目标
  • 嘗試對源 store 建立 leader 遷出的任務,如果無法遷出則嘗試對目标 store 建立遷入任務
  • balance-region: server/scheduler/balance_region.go
  • 從所有的 store 中挑選出來目前 region score 最高的節點作為遷移的源節點
  • 查找是否存在 pending 的 region,有的話随機挑選一個 pending region 排程走
  • 查找是否存在 follower region,有的話随機挑選一個 follower region 排程走
  • 如果前兩步選擇出的 region 副本數同叢集設定副本數不同,說明對應的 region 正在調整過程中,跳過這個 region 重新選擇
  • 如果選擇的 region 是目前的熱點 region,為了避免排程對 region 産生額外的壓力跳過這個 region 重新選擇
  • 确認選擇的 region 有滿足叢集放置政策的合适遷移目标,如果不存在合适目标則跳過這個 region 重新選擇
  • 建立遷移 region 的排程任務
  • evict-leader: server/scheduler/evict_leader.go
  • 在 store 的 region 中随機挑選一個 leader region
  • 選擇對應 region 中的一個 follower 作為新的 leader
  • 建立遷移 leader 的排程任務
  • grant-leader: server/scheduler/grant_leader.go
  • 在 store 的 region 中随機挑選一個 follower region
  • 建立遷移 leader 到目前 store 的排程任務
  • hot-region: server/scheduler/hot_region.go
  • 随機決定做讀熱點排程還是寫熱點排程
  • 根據 region 的統計資訊進行熱度打分
  • 根據打分資訊挑選一個候選節點進行排程操作
  • 選擇遷移的目标建立排程排程任務
  • label: server/scheduler/label.go
  • 從所有的 store 中篩選出包含 reject-leader 屬性的 store
  • 周遊滿足篩選條件的 store,在目前 store 上随機挑選一個 leader 并選擇目标 store 建立排程任務
  • random-merge: server/scheduler/random_merge.go
  • 随機挑選一個 store
  • 在 store 上随機挑選一個 leader region 并擷取它的相鄰 region
  • 建立 region 合并任務
  • scatter-range: server/scheduler/scatter_range.go
  • 收集指定 key 區間内的 region 資訊
  • 建立将區間内的 leader 打散的任務
  • 建立将區間内的 follower 打散的任務
  • shuffle_hot_region: server/scheduler/shuffle_hot_region.go
  • 随機決定做讀熱點排程還是寫熱點排程
  • 根據 region 的統計資訊進行熱度打分
  • 随機挑選一個候選節點進行排程操作
  • 選擇遷移的目标建立排程排程任務
  • shuffle_leader: server/scheduler/shuffle_leader.go
  • 随機挑選一個 store
  • 在 store 上随機挑選一個 follower region
  • 建立将 follower region 變成 leader 的排程任務
  • shuffle_region: server/scheduler/shuffle_region.go
  • 随機挑選一個 store
  • 在 store 上随機挑選一個 region
  • 根據政策挑選一個目标 store
  • 建立遷移 region 到目标 store 的排程任務