###################

每个 node 会定期的将自己机器上的 region 信息通过心跳发送给 pd, pd 通过各个 node 通过心跳传上来的 region 信息建立一个全局的路由表。

这样即使 pd 挂掉,新的 pd 启动起来后,只需要等待几个心跳时间,就又可以拥有全局的路由信息,

另外 etcd 可以作为缓存加速这一过程,也就是新的 pd 启动后,先从 etcd 上拉取一遍路由信息,然后等待几个心跳,就可以对外提供服务。

 

Placement Driver ,后续以 PD 简称,集成了etcd,彻底无状态服务, 是 TiDB 里面全局中心总控节点的地位

核心功能有:

1)它负责整个集群的调度;

2)负责全局 ID 的生成;

3)全局时间戳 TSO 授时的生成,且TSO单调递增,是int64类型=毫秒时间+逻辑时间1<<18,也就是说 1ms,PD 最多可以分配 262144 个 TSO,这个能满足绝大多数情况了。每秒能分配百万级别的 TSO;

4)PD 还保存着整个集群 TiKV 的元信息;

5)全局路由信息,负责给 client 提供路由功能。

6)提供故障自动切换和数据强一致性保障。因集成了etcd,支持故障自动切换,无需担心单点故障问题。通过 etcd 的 raft,保证了数据的强一致性,不用担心数据丢失的问题。

PD的数据来源:

1)PD 所有的数据都是通过 TiKV 主动上报获知的。

2)PD 对整个 TiKV 集群的调度等操作,也只会在 TiKV 发送 heartbeat 命令的结果里面返回相关的命令,让 TiKV 自行去处理,而不是主动去给 TiKV 发命令,所有的操作都是被动触发,即使 PD 挂掉,新选出的 PD leader 也能立刻对外服务,无需考虑任何之前的中间状态。(像个癞蛤蟆,跺一下跳一下)

 

 

 

 

PD集群的初始化:

假设现在我们有三个pd实例,分别为 pd1,pd2,pd3,分别在 host1,host2,host3 上面:

host1   pd1

host2   pd2

host3   pd3

 

因为PD 集成了 etcd服务,所以通常,我们需要启动至少三个副本,才能保证数据的安全。现阶段 PD 有:集群启动方式、initial-cluster的静态方式、 join的动态方式。

在 etcd 里面,默认要监听 2379 和 2380 两个端口。2379 主要是 etcd 用来处理外部请求用的,而 2380 则是 etcd peer 之间相互通信用的。

1)静态初始化方式initial-cluster:2380

我们直接在三个 PD 启动的时候,给 initial-cluster配置为:
 
pd1
=http://host1:2380,pd2=http://host2:2380,pd3=http://host3:2380

 

2)动态初始化方式join:2379

对于动态初始化:

1)我们先启动 pd1,

2)然后启动 pd2,加入到 pd1 的集群里面,join设置为  pd1=http://host1:2379。

3)然后启动 pd3,加入到 pd1,pd2 形成的集群里面,join设置为 pd1=http://host1:2379

 

3)两种方式注意事项:

1)互斥关系:静态初始化和动态初始化完全走的是两个端口,而且这两个是互斥的,也就是我们只能使用一种方式来初始化集群。

2)join是pd提供,静态方式是etcd提供:etcd 本身只支持 initial-cluster的方式,但为了方便,PD 同时也提供了 join的方式。

3)etcd使用2380,join通过2379端口发送命令执行:join主要是用了 etcd 自身提供的 member 相关 API,包括 add member,list member 等,所以我们使用 2379 端口,因为需要将命令发到 etcd 去执行。而 initial-cluster则是 etcd 自身的初始化方式,所以使用的 2380 端口。

4)优先选择join方式:相比于 initial-cluster,join需要考虑非常多的 case(在 server/join.goprepareJoinCluster函数里面有详细的解释),但 join的使用非常自然,后续我们会考虑去掉 initial-cluster的初始化方案。

 

 

 

 

 

 

 

 

 

 

 

####################