PD:有高可用和强一致性。 也有leader。使用奇数的节点数量。它需要存储元数据,分配全局时钟(TSO),调度Region。
名词概念:
store: 指的是TiKV 节点,或者说TiKV实例
Peer: 一个副本就是一个peer,也指raft当中的成员。
路由功能:简单而言,就是执行SQL的时候,Leader region在哪个TiKV上。
Region Cache: 为了减轻PD与TiDBServer的交互,将一些Region 信息缓存在这。当然这里面有可能信息过旧。需要重新从PD中载入。 这个时间消耗属于back off一种。
TSO = physical time logical time
tso int64 unix 时钟 locical time: 把1ms分成262144个TSO。
PD (Placement Driver) 是 TiDB 集群的管理模块,同时
tsFuture的作用: 如果要等TSO返回,则可能会有延时,改进措施,会立即返回tsFutrue,这个tsFuture会标识 我在什么时候请求了一个TSO。此时SQL语句就该干什么就做什么不用等待获得的TSO。 此时就解析编译,生成执行计划。 在这期间pd client就赶紧拿着这个请求需求去PD,来获得TSO。 获得TSO 和执行计划后,就可以执行SQL语句。
如果获得TSO 比较快,而解析编译还没完成,会等待下tsFutrue.wait(在解析编译后才会获得),得到tsFutrue.wait后才会将请求到的TSO 获得到。
问题:
这时候可以看到磁盘的IO就是3秒一次。 意思就是将一段时间的TSO 分配到缓存中,供TiDB Server排队获取。
调度依赖于整个集群信息的收集,简单来说,调度需要知道每个 TiKV 节点的状态以及每个Region 的状态。TiKV 集群会向 PD 汇报两类消息,TiKV 节点信息和Region 信息:
每个 TiKV 节点会定期向 PD 汇报节点的状态信息
TiKV 节点 (Store) 与 PD 之间存在⼼跳包,⼀⽅⾯ PD 通过⼼跳包检测每个 Store 是否存活,以及是否有新加⼊的 Store;另⼀⽅⾯,⼼跳包中也会携带这个 Store 的状态信息,主要包括:
通过使⽤ pd-ctl 可以查看到 TiKV Store 的状态信息。TiKV Store 的状态具体分为Up,Disconnect,Offline,Down,Tombstone。各状态的关系如下:
每个 Raft Group 的 Leader 会定期向 PD 汇报 Region 的状态信息
每个 Raft Group 的 Leader 和 PD 之间存在⼼跳包,⽤于汇报这个 Region 的状态,主要包括下⾯⼏点信息:
PD 不断的通过这两类⼼跳消息收集整个集群的信息,再以这些信息作为决策的依据。
除此之外,PD 还可以通过扩展的接⼝接受额外的信息,⽤来做更准确的决策。⽐如当某个 Store 的⼼跳包中断的时候,PD 并不能判断这个节点是临时失效还是永久失效,只能经过⼀段时间的等待(默认是 30 分钟),如果⼀直没有⼼跳包,就认为该 Store 已经下线,再决定需要将这个 Store 上⾯的 Region 都调度⾛。
但是有的时候,是运维⼈员主动将某台机器下线,这个时候,可以通过 PD 的管理接⼝通知 PD 该 Store 不可⽤,PD 就可以⻢上判断需要将这个 Store 上⾯的 Region都调度⾛。
PD 不断地通过 Store 或者 Leader 的⼼跳包收集整个集群信息,并且根据这些信息以及调度策略⽣成调度操作序列。每次收到 Region Leader 发来的⼼跳包时,PD 都会检查这个 Region 是否有待进⾏的操作,然后通过⼼跳包的回复消息,将需要进⾏的操作返回给 Region Leader,并在后⾯的⼼跳包中监测执⾏结果。
注意这⾥的操作只是给 Region Leader 的建议,并不保证⼀定能得到执⾏,具体是否会执⾏以及什么时候执⾏,由 Region Leader 根据当前⾃身状态来定。
对常见问题和场景进⾏分类和整理,可归为以下两类:
第⼀类:作为⼀个分布式⾼可⽤存储系统,必须满⾜的需求,包括⼏种
第⼆类:作为⼀个良好的分布式系统,需要考虑的地⽅包括
满⾜第⼀类需求后,整个系统将具备强⼤的容灾功能。满⾜第⼆类需求后,可以使得系统整体的资源利⽤率更⾼且合理,具备良好的扩展性。
为了满⾜这些需求,⾸先需要收集⾜够的信息,⽐如每个节点的状态、每个 Raft Group 的信息、业务访问操作的统计等;其次需要设置⼀些策略,PD 根据这些信息以及调度的策略,制定出尽量满⾜前⾯所述需求的调度计划;最后需要⼀些基本的操作,来完成调度计划。
调度类型大概有以下一些:
调度的基本操作指的是为了满⾜调度的策略。上述调度需求可整理为以下三个操作:
刚好 Raft 协议通过 AddReplica 、 RemoveReplica 、 TransferLeader 这三个命令,可以⽀撑上述三种基本操作。
PD 收集了这些信息后,还需要⼀些策略来制定具体的调度计划。
⼀个 Region 的副本数量正确
当 PD 通过某个 Region Leader 的⼼跳包发现这个 Region 的副本数量不满⾜要求时,需要通过 Add/Remove Replica 操作调整副本数量。出现这种情况的可能原因是:
⼀个 Raft Group 中的多个副本不在同⼀个位置
注意这⾥⽤的是『同⼀个位置』⽽不是『同⼀个节点』,这个位置指的是地理位置。在⼀般情况下,PD 只会保证多个副本不落在⼀个节点上,以避免单个节点失效导致多个副本丢失。在实际部署中,还可能出现下⾯这些需求:
这些需求本质上都是某⼀个节点具备共同的位置属性,构成⼀个最⼩的『容错单元』,希望这个单元内部不会存在⼀个 Region 的多个副本。这个时候,可以给节点配置 labels并且通过在 PD 上配置 location-labels来指名哪些 label 是位置标识,需要在副本分配的时候尽量保证⼀个 Region 的多个副本不会分布在具有相同的位置标识的节点上。
副本在 Store 之间的分布均匀分配
由于每个 Region 的副本中存储的数据容量上限是固定的,通过维持每个节点上⾯副本数量的均衡,使得各节点间承载的数据更均衡。
Leader 数量在 Store 之间均匀分配
Raft 协议要求读取和写⼊都通过 Leader 进⾏,所以计算的负载主要在 Leader 上⾯,PD 会尽可能将 Leader 在节点间分散开。
访问热点数量在 Store 之间均匀分配
每个 Store 以及 Region Leader 在上报信息时携带了当前访问负载的信息,⽐如 Key的读取/写⼊速度。PD 会检测出访问热点,且将其在节点之间分散开。
各个 Store 的存储空间占⽤⼤致相等
每个 Store 启动的时候都会指定⼀个 Capacity 参数,表明这个 Store 的存储空间上限,PD 在做调度的时候,会考虑节点的存储空间剩余量。
控制调度速度,避免影响在线服务
调度操作需要耗费 CPU、内存、磁盘 IO 以及⽹络带宽,需要避免对线上服务造成太⼤影响。PD 会对当前正在进⾏的操作数量进⾏控制,默认的速度控制是⽐较保守的,如果希望加快调度(⽐如停服务升级或者增加新节点,希望尽快调度),那么可以通过调节 PD 参数动态加快调度速度。
以上问题和场景如果多个同时出现,就不太容易解决,因为需要考虑全局信息。同时整个系统也是在动态变化的,因此需要⼀个中⼼节点,来对系统的整体状况进⾏把控和调整,所以有了 PD 这个模块。
isolation-level 隔离级别,设置为zone,则副本在zone(当前是数据中心DC) 的级别必须要隔离。
负责集群数据的实时调度。
TiKV 集群是 TiDB 数据库的分布式 KV 存储引擎,数据以 Region 为单位进⾏复制和管理,每个 Region 会有多个副本 (Replica),这些副本会分布在不同的 TiKV 节点上,其中 Leader 负责读/写,Follower 负责同步 Leader 发来的 Raft log。
需要考虑以下场景: