写点什么

TiDB PD 组件代码阅读

  • 2022 年 7 月 11 日
  • 本文字数:4325 字

    阅读完需:约 14 分钟

作者: sunxiaoguang 原文来源:https://tidb.net/blog/a19e33e6


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


IsScheduleAllowed(cluster Cluster) bool


}


各个调度器的主体调度逻辑实现在 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 的调度任务


发布于: 刚刚阅读数: 2
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
TiDB PD 组件代码阅读_TiDB 社区干货传送门_InfoQ写作社区