做者:黄梦龙git
众所周知,PD 是整个 TiDB 集群的核心,负责全局元信息的存储以及 TiKV 集群负载均衡调度,本文将详细介绍 PD 调度系统的原理,并经过几个典型场景的分析和处理方式,分享调度策略的最佳实践和调优方法,帮助你们在使用过程当中快速定位问题。本文内容基于 3.0 版本,更早的版本(2.x)缺乏部分功能的支持,可是基本原理相似,也能够以本文做为参考。github
首先咱们介绍一下调度系统涉及到的相关概念,理解这些概念以及它们相互之间的关系,有助于在实践中快速定位问题并经过配置进行调整。api
PD 中的 Store 指的是集群中的存储节点,也就是 tikv-server 实例。注意 Store 与 TiKV 实例是严格一一对应的,即便在同一主机甚至同一块磁盘部署多个 TiKV 实例,这些实例也会对应不一样的 Store。安全
每一个 Region 负责维护集群的一段连续数据(默认配置下平均约 96 MiB),每份数据会在不一样的 Store 存储多个副本(默认配置是 3 副本),每一个副本称为 Peer。同一个 Region 的多个 Peer 经过 raft 协议进行数据同步,因此 Peer 也用来指代 raft 实例中的成员。TiKV 使用 multi-raft 模式来管理数据,即每一个 Region 都对应一个独立运行的 raft 实例,咱们也把这样的一个 raft 实例叫作一个 Raft Group。网络
它们分别对应 Peer 的三种角色。其中 Leader 负责响应客户端的读写请求;Follower 被动地从 Leader 同步数据,当 Leader 失效时会进行选举产生新的 Leader;Learner 是一种特殊的角色,它只参与同步 raft log 而不参与投票,在目前的实现中只短暂存在于添加副本的中间步骤。并发
TiKV 集群中的 Region 不是一开始就划分好的,而是随着数据写入逐渐分裂生成的,分裂的过程被称为 Region Split。app
其机制是集群初始化时构建一个初始 Region 覆盖整个 key space,随后在运行过程当中每当 Region 数据达到必定量以后就经过 Split 产生新的 Region。负载均衡
Pending 和 Down 是 Peer 可能出现的两种特殊状态。其中 Pending 表示 Follower 或 Learner 的 raft log 与 Leader 有较大差距,Pending 状态的 Follower 没法被选举成 Leader。Down 是指 Leader 长时间没有收到对应 Peer 的消息,一般意味着对应节点发生了宕机或者网络隔离。工具
Scheduler性能
Scheduler(调度器)是 PD 中生成调度的组件。PD 中每一个调度器是独立运行的,分别服务于不一样的调度目的。经常使用的调度器及其调用目标有:
balance-leader-scheduler
:保持不一样节点的 Leader 均衡。balance-region-scheduler
:保持不一样节点的 Peer 均衡。hot-region-scheduler
:保持不一样节点的读写热点 Region 均衡。evict-leader-{store-id}
:驱逐某个节点的全部 Leader。(经常使用于滚动升级)Operator 是应用于一个 Region 的,服务于某个调度目的的一系列操做的集合。例如“将 Region 2 的 Leader 迁移至 Store 5”,“将 Region 2 的副本迁移到 Store 1, 4, 5” 等。
Operator 能够是由 Scheduler 经过计算生成的,也能够是由外部 API 建立的。
Operator Step
Operator Step 是 Operator 执行过程的一个步骤,一个 Operator 经常会包含多个 Operator Step。
目前 PD 可生成的 Step 包括:
TransferLeader
:将 Region Leader 迁移至指定 PeerAddPeer
:在指定 Store 添加 FollowerRemovePeer
:删除一个 Region PeerAddLearner
:在指定 Store 添加 Region LearnerPromoteLearner
:将指定 Learner 提高为 FollowerSplitRegion
:将指定 Region 一分为二宏观上来看,调度流程大致可划分为 3 个部分:
1. 信息收集
TiKV 节点周期性地向 PD 上报 StoreHeartbeat
和 RegionHeartbeat
两种心跳消息。其中 StoreHeartbeat
包含了 Store 的基本信息,容量,剩余空间,读写流量等数据,RegionHeartbeat
包含了 Region 的范围,副本分布,副本状态,数据量,读写流量等数据。PD 将这些信息梳理并转存供调度来决策。
2. 生成调度
不一样的调度器从自身的逻辑和需求出发,考虑各类限制和约束后生成待执行的 Operator。这里所说的限制和约束包括但不限于:
3. 执行调度
生成的 Operator 不会当即开始执行,而是首先会进入一个由 OperatorController
管理的一个等待队列。OperatorController
会根据配置以必定的并发从等待队列中取出 Operator 进行执行,执行的过程就是依次把每一个 Operator Step 下发给对应 Region 的 Leader。
最终 Operator 执行完毕会被标记为 finish 状态或者超时被标记为 timeout,并从执行列表中移除。
Region 负载均衡调度主要依赖 balance-leader
和 balance-region
这两个调度器,这两者的调度目标是将 Region 均匀地分散在集群中的全部 Store 上。它们的侧重点又有所不一样:balance-leader
关注 Region 的 Leader,能够认为目的是分散处理客户端请求的压力;balance-region
关注 Region 的各个 Peer,目的是分散存储的压力,同时避免出现爆盘等情况。
balance-leader
与 balance-region
有着相似的调度流程,首先根据不一样 Store 的对应资源量的状况分别打一个分,而后不断从得分较高的 Store 选择 Leader 或 Peer 迁移到得分较低的 Store 上。
这二者的分数计算上也有必定差别:balance-leader
比较简单,使用 Store 上全部 Leader 所对应的 Region Size 加和做为得分;balance-region
因为要考虑不一样节点存储容量可能不一致的状况,会分三种状况,当空间富余时使用数据量计算得分(使不一样节点数据量基本上均衡),当空间不足时由使用剩余空间计算得分(使不一样节点剩余空间基本均衡),处于中间态时则同时考虑两个因素作加权和看成得分。
此外,为了应对不一样节点可能在性能等方面存在差别的问题,咱们还支持为 Store 设置 balance 权重。leader-weight
和 region-weight
分别用于控制 leader 权重以及 region 权重,这两个配置的默认值都为 1
。假如把某个 Store 的 leader-weight
设为 2
,调度稳定后,则该节点的 leader 数量约为普通节点的 2 倍;假如把某个 Store 的 region-weight
设为 0.5
,那么调度稳定后该节点的 region 数量约为其余节点的一半。
热点调度对应的调度器是 hot-region-scheduler
。目前 3.0 版本统计热点 Region 的方式比较单一,就是根据 Store 上报的信息,统计出持续一段时间读或写流量超过必定阈值的 Region,而后再用与 Balance 相似的方式把这些 Region 分散开来。
对于写热点,热点调度会同时尝试打散热点 Region 的 Peer 和 Leader;对于读热点,因为只有 Leader 承载读压力,热点调度会尝试将热点 Region 的 Leader 打散。
让 PD 感知不一样节点分布的拓扑是为了经过调度使不一样 Region 的各个副本尽量分散,保证高可用和容灾。例如集群有 3 个数据中心,最安全的调度方式就是把 Region 的 3 个 Peer 分别放置在不一样的数据中心,这样任意一个数据中心故障时,都能继续提供服务。
PD 会在后台不断扫描全部 Region,当发现 Region 的分布不是当前的最优化状态时,会生成调度替换 Peer,将 Region 调整至最佳状态。
负责这个检查的组件叫 replicaChecker
(跟 Scheduler 相似,可是不可关闭),它依赖于 location-labels
这个配置来进行调度。好比配置 [zone, rack, host]
定义了三层的拓扑结构:集群分为多个 zone(可用区),每一个 zone 下有多个 rack(机架),每一个 rack 下有多个 host(主机)。PD 在调度时首先会尝试将 Region 的 Peer 放置在不一样的 zone,假如没法知足(好比配置 3 副本但总共只有 2 个 zone)则退而求其次保证放置在不一样的 rack,假如 rack 的数量也不足以保证隔离,那么再尝试 host 级别的隔离,以此类推。
缩容是指预备将某个 Store 下线,经过命令将该 Store 标记为 Offline
状态,此时 PD 经过调度将待下线节点上的 Region 迁移至其余节点。故障恢复是指当有 Store 发生故障且没法恢复时,有 Peer 分布在对应 Store 上的 Region 会产生缺乏副本的情况,此时 PD 须要在其余节点上为这些 Region 补副本。
这两种状况的处理过程基本上是同样的。由 replicaChecker
检查到 Region 存在异常状态的 Peer,而后生成调度在健康的 Store 建立新副本替换掉异常的。
Region merge 指的是为了不删除数据后大量小 Region 甚至空 Region 消耗系统资源,经过调度把相邻的小 Region 合并的过程。Region merge 由 mergeChecker
负责,其过程与 replicaChecker
相似,也是在后台遍历,发现连续的小 Region 后发起调度。
查看调度系统的状态的手段主要包括:Metrics,pd-ctl,日志。本文简要介绍 Metrics 和 pd-ctl 两种方式,更具体的信息能够参考官方文档中 PD 监控 以及 PD Control 使用 的章节。
Grafana PD / Operator 页面展现了 Operator 相关统计。其中比较重要的有:
Schedule Operator Create
:展现 Operator 的建立状况,从名称能够知道 Operator 是哪一个调度器建立的以及建立的缘由。Operator finish duration
:展现了 Operator 执行耗时的状况Operator Step duration
:展现不一样 Operator Step 执行耗时的状况查询 Operator 的 pd-ctl 命令有:
operator show
:查询当前调度生成的全部 Operatoroperator show [admin | leader | region]
:按照类型查询 OperatorGrafana PD / Statistics - Balance 页面展现了负载均衡相关统计,其中比较重要的有:
Store Leader/Region score
:展现每一个 Store 的得分Store Leader/Region count
:展现每一个 Store 的 Leader/Region 数量Store available
:展现每一个 Store 的剩余空间使用 pd-ctl 的 store 命令能够查询 Store 的得分,数量,剩余空间,weight 等信息。
Grafana PD / Statistics - hotspot 页面展现了热点 Region 的相关统计,其中比较重要的有:
Hot write Region’s leader/peer distribution
:展现了写热点 Region 的 Leader/Peer 分布状况Hot read Region’s leader distribution
:展现了读热点 Region 的 Leader 分布状况使用 pd-ctl 一样能够查询上述信息,可使用的命令有:
hot read
:查询读热点 Region 信息hot write
:查询写热点 Region 信息hot store
:按 Store 统计热点分布状况region topread [limit]
:查询当前读流量最大的 Regionregion topwrite [limit]
:查询当前写流量最大的 RegionGrafana PD / Cluster / Region health 面板展现了异常状态 Region 数的统计,其中包括 Pending Peer,Down Peer,Offline Peer,以及副本数过多或过少的 Region。
经过 pd-ctl 的 region check 命令能够查看具体异常的 Region 列表:
region check miss-peer
:缺副本的 Regionregion check extra-peer
:多副本的 Regionregion check down-peer
:有副本状态为 Down 的 Regionregion check pending-peer
:有副本状态为 Pending 的 Region在线调整调度策略主要使用 pd-ctl 工具来完成,能够经过如下 3 个方面来控制 PD 的调度行为。本文作一些简要介绍,更具体的信息能够参考官方文档中 PD Control 使用 的章节。
pd-ctl 支持动态建立和删除 Scheduler 的功能,咱们能够经过这些操做来控制 PD 的调度行为,以下所示:
scheduler show
:显示当前系统中的 Schedulerscheduler remove balance-leader-scheduler
:删除(停用)balance leader 调度器scheduler add evict-leader-scheduler-1
:添加移除 Store 1 的全部 Leader 的调度器PD 还支持绕过调度器,直接经过 pd-ctl 来建立或删除 Operator,以下所示:
operator add add-peer 2 5
:在 Store 5 上为 Region 2 添加 Peeroperator add transfer-leader 2 5
:将 Region 2 的 Leader 迁移至 Store 5operator add split-region 2
:将 Region 2 拆分为 2 个大小至关的 Regionoperator remove 2
:取消 Region 2 当前待执行的 Operator使用 pd-ctl 执行 config show
命令能够查看全部的调度参数,执行 config set {key} {value}
能够调整对应参数的值。这里举例说明常见的参数,更详情的说明请参考 PD 调度参数指南:
leader-schedule-limit
:控制 Transfer Leader 调度的并发数region-schedule-limit
:控制增删 Peer 调度的并发数disable-replace-offline-replica
:中止处理节点下线的调度disable-location-replacement
:中止处理调整 Region 隔离级别相关的调度max-snapshot-count
:每一个 Store 容许的最大收发 Snapshot 的并发数须要说明的是,PD 的打分机制决定了通常状况下,不一样 Store 的 Leader Count 和 Region Count 不同多并不表明负载是不均衡的。须要从 TiKV 的实际负载或者存储空间占用来判断是否有 Balance 不均衡的情况。
确认存在 Leader / Region 分布不均衡的现象后,首先要观察不一样 Store 的打分状况。
若是不一样 Store 的打分是接近的,说明 PD 认为此时已是均衡状态了,可能的缘由有:
leader-weight
和 region-weight
来控制 Leader / Region 的分布。若是不一样 Store 的打分差别较大,须要进一步检查 Operator 相关 Metrics,特别关注 Operator 的生成和执行状况,这时大致上又分两种状况。
一种状况是生成的调度是正常的,可是调度的速度很慢。可能的缘由有:
leader-schedule-limit
或 region-schedule-limit
调大一些,此外, max-pending-peer-count
以及 max-snapshot-count
限制也能够放宽。region-schedule-limit
配额,此时咱们能够把 replica-schedule-limit
调小将下线调度的速度限制住,或者干脆设置 disable-replace-offline-replica = true
来暂时关闭下线流程。TransferLeader
,RemovePeer
,PromoteLearner
等)的完成时间应该在毫秒级,涉及到 Snapshot 的 Step(如 AddLearner
,AddPeer
等)的完成时间为数十秒。若是耗时明显太高,多是 TiKV 压力过大或者网络等方面的瓶颈致使的,须要具体状况具体分析。另外一种状况是没能生成对应的 balance 调度。可能的缘由有:
0
。evict-leader-scheduler
,此时没法把 Leader 迁移至对应的 Store。再好比设置了 Label property,也会致使部分 Store 不接受 Leader。这个场景仍是从 Operator 相关 Metrics 入手,分析 Operator 的生成执行状况。
若是调度在正常生成,只是速度很慢。可能的缘由有:
replica-schedule-limit
,能够把它适当调大。与 Balance 相似,max-pending-peer-count
以及 max-snapshot-count
限制一样也能够放宽。evict-leader
调度迁走 Leader 来加速。若是没有对应的 Operator 调度生成,可能的缘由有:
replica-schedule-limit
被设为 0。目前 PD 没有对节点上线特殊处理,节点上线实际上就是依靠 balance region 机制来调度的,因此参考前面 Region 分布不均衡的排查步骤便可。
热点调度的问题大致上能够分为如下几种状况。
一种是从 PD 的 metrics 能看出来有很多 hot Region,可是调度速度跟不上,不能及时地把热点 Region 分散开来。
解决方法是加大 hot-region-schedule-limit
,并减小其余调度器的 limit 配额,从而加快热点调度的速度。还有 hot-region-cache-hits-threshold
调小一些可使 PD 对流量的变化更快作出反应。
第二种状况是单一 Region 造成热点的状况,好比大量请求频繁 scan 一个小表。这个能够从业务角度或者 metrics 统计的热点信息看出来。因为单 Region 热点现阶段没法使用打散的手段来消除,须要确认热点 Region 后先手动添加 split-region
调度将这样的 Region 拆开。
还有一种状况是从 PD 的统计来看没有热点,可是从 TiKV 的相关 metrics 能够看出部分节点负载明显高于其余节点,成为整个系统的瓶颈。
这是由于目前 PD 统计热点 Region 的维度比较单一,仅针对流量进行分析,在某些场景下没法准备定位出热点。例如部分 Region 有大量的点查请求,从流量上来看并不显著,可是太高的 QPS 致使关键模块达到瓶颈。这个问题当前的处理方式是:首先从业务层面肯定造成热点的 table,而后添加 scatter-range-scheduler
来使得这个 table 的全部 Region 均匀分布。TiDB 也在其 HTTP API 中提供了相关接口来简化这个操做,具体能够参考 TiDB HTTP API 文档。
与前面讨论过的全部调度慢的问题相似,Region Merge 速度慢也颇有多是受到 limit 限制(Region Merge 同时受限于 merge-schedule-limit
及 region-schedule-limit
),或者是与其余调度器产生了竞争,处理方法再也不赘述了。
假如咱们已经从统计得知系统中有大量的空 Region,这时能够经过把 max-merge-region-size
和 max-merge-region-keys
调整为较小值来加快 Merge 速度。这是由于 Merge 的过程涉及到副本迁移,因而 Merge 的 Region 越小,速度就越快。若是 Merge Operator 生成的速度已经有几百 opm,想进一步加快,还能够把 patrol-region-interval
调整为 "10ms" ,这个能加快巡检 Region 的速度,可是会消耗更多的 CPU。
还有一种特殊状况:曾经建立过大量 Table 而后又清空了(truncate 操做也算建立 Table),此时若是开启了 split table 特性,这些空 Region 是没法合并的,此时须要调整如下参数关闭这个特性:
split-region-on-table
设为 false
namespace-classifier
设为 “”
另外对于 3.0.4 和 2.1.16 之前的版本,Region 的统计 approximate_keys
在特定状况下(大部分发生在 drop table 以后)统计不许确,形成 keys 的统计值很大,没法知足 max-merge-region-keys
的约束,能够把 max-merge-region-keys
这个条件放开,调成很大的值来绕过这个问题。
没有人工介入时,PD 处理 TiKV 节点故障的默认行为是,等待半小时以后(可经过 max-store-down-time
配置调整),将此节点设置为 Down
状态,并开始为涉及到的 Region 补充副本。
实践中,若是能肯定这个节点的故障是不可恢复的,能够当即作下线处理,这样 PD 能尽快补齐副本,下降数据丢失的风险。与之相对,若是肯定这个节点是能恢复的,但可能半小时以内来不及,则能够把 max-store-down-time
临时调整为比较大的值,这样能避免超时以后产生没必要要的补副本产生资源浪费。
本文介绍了 PD 调度的概念,原理以及常见问题的处理方法,但愿读者能够在理解调度系统的基础上,参考本文按图索骥解决生产中遇到的调度相关的问题。PD 的调度策略还在不断的演进和完善中,也期待你们踊跃提出宝贵的改进意见。
原文阅读:https://pingcap.com/blog-cn/best-practice-pd/