TiDB 整体架构及主要特性

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TiDB 整体架构及主要特性相关的知识,希望对你有一定的参考价值。

参考技术A 首先,贴出的是TiDB的架构图。TiDB 集群主要包括三个核心组件:TiDB Server,PD Server 和 TiKV Server。此外,还有用于解决用户复杂 OLAP 需求的 TiSpark 组件。

TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑,并通过 PD 找到存储计算所需数据的 TiKV 地址,与 TiKV 交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如LVS、HAProxy 或 F5)对外提供统一的接入地址。

Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个:一是存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);二是对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);三是分配全局唯一且递增的事务 ID。
PD 通过 Raft 协议保证数据的安全性。Raft 的 leader server 负责处理所有操作,其余的 PD server 仅用于保证高可用。建议部署奇数个 PD 节点。

TiKV Server 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range(从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region。TiKV 使用 Raft 协议做复制,保持数据的一致性和容灾。副本以 Region 为单位进行管理,不同节点上的多个 Region 构成一个 Raft Group,互为副本。数据在多个 TiKV 之间的负载均衡由 PD 调度,这里也是以 Region 为单位进行调度。

TiSpark 作为 TiDB 中解决用户复杂 OLAP 需求的主要组件,将 Spark SQL 直接运行在 TiDB 存储层上,同时融合 TiKV 分布式集群的优势,并融入大数据社区生态。至此,TiDB 可以通过一套系统,同时支持 OLTP 与 OLAP,免除用户数据同步的烦恼。

TiDB 有两大两大核心特性:水平扩展与高可用。

无限水平扩展是 TiDB 的一大特点,这里说的水平扩展包括两方面:计算能力和存储能力。TiDB Server 负责处理 SQL 请求,随着业务的增长,可以简单的添加TiDB Server 节点,提高整体的处理能力,提供更高的吞吐。TiKV 负责存储数据,随着数据量的增长,可以部署更多的 TiKV Server 节点解决数据 Scale 的问题。PD 会在 TiKV 节点之间以 Region 为单位做调度,将部分数据迁移到新加的节点上。所以在业务的早期,可以只部署少量的服务实例(推荐至少部署 3 个 TiKV,3 个 PD,2 个 TiDB),随着业务量的增长,按照需求添加 TiKV 或者 TiDB 实例。

高可用是 TiDB 的另一大特点,TiDB/TiKV/PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。下面分别说明这三个组件的可用性、单个实例失效后的后果以及如何恢复。

TiDB 架构及设计实现

一. TiDB的核心特性

高度兼容 MySQL

     大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。

水平弹性扩展

     通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。

分布式事务

     TiDB 100% 支持标准的 ACID 事务。

高可用

     相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复 (auto-failover),无需人工介入。

一站式 HTAP 解决方案

    TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP 解决方案,一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程。

云原生 SQL 数据库

           TiDB 是为云而设计的数据库,同 Kubernetes 深度耦合,支持公有云、私有云和混合云,使部署、配置和维护变得十分简单。

二.TiDB 整体架构

TiDB Server

     TiDB Server 负责接收SQL请求,处理SQL相关的逻辑,并通过PD找到存储计算所需数据的TiKV地址,与TiKV交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(LVS、HAProxy或F5)对外提供统一的接入地址。

PD Server

     Placement Driver(简称PD)是整个集群的管理模块,其主要工作有三个:一是存储集群的元信息(某个Key存储在那个TiKV节点);二是对TiKV集群进行调度和负载均衡(如数据的迁移、Raft group leader的迁移等);三是分配全局唯一且递增的事务ID。

PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署3个节点。PD在选举的过程中无法对外提供服务,这个时间大约是3

TiKV Server

     TiKV Server 负责存储数据,从外部看TiKV是一个分布式的提供事务的Key-Value存储引擎。存储数据的基本单位是Region,每个Region负责存储一个Key Range(从StartKey到EndKey的左闭右开区间)的数据,每个TiKV节点会负责多个Region。TiKV使用Raft协议做复制,保持数据的一致性和容灾。副本以Region为单位进行管理,不同节点上的多个Region构成一个Raft Group,互为副本。数据在多个TiKV之间的负载均衡由PD调度,这里也就是以Region为单位进行调度

 

三. 存储结构

一个 Region 的多个 Replica 会保存在不同的节点上,构成一个 Raft Group。其中一个 Replica 会作为这个 Group 的 Leader,其他的 Replica 作为 Follower。所有的读和写都是通过 Leader 进行,再由 Leader 复制给 Follower。

Key-Value 模型

TiDB对每个表分配一个TableID,每一个索引都会分配一个IndexID,每一行分配一个RowID(如果表有整形的Primary Key,那么会用Primary Key的值当做RowID),其中TableID在整个集群内唯一,IndexID/RowID 在表内唯一,这些ID都是int64类型。每行数据按照如下规则进行编码成Key-Value pair:

Key: tablePrefix_rowPrefix_tableID_rowID

Value: [col1, col2, col3, col4]

其中Key的tablePrefix/rowPrefix都是特定的字符串常量,用于在KV空间内区分其他数据。对于Index数据,会按照如下规则编码成Key-Value pair

Key: tablePrefix_idxPrefix_tableID_indexID_indexColumnsValue

Value: rowID

Index 数据还需要考虑Unique Index 和 非 Unique Index两种情况,对于Unique Index,可以按照上述编码规则。但是对于非Unique Index,通常这种编码并不能构造出唯一的Key,因为同一个Index的tablePrefix_idxPrefix_tableID_indexID_都一样,可能有多行数据的ColumnsValue都是一样的,所以对于非Unique Index的编码做了一点调整:

Key: tablePrefix_idxPrefix_tableID_indexID_ColumnsValue_rowID

Value:null

这样能够对索引中的每行数据构造出唯一的Key。注意上述编码规则中的Key里面的各种xxPrefix都是字符串常量,作用都是用来区分命名空间,以免不同类型的数据之间互相冲突,定义如下:

var(

tablePrefix     = []byte{\'t\'}

recordPrefixSep = []byte("_r")

indexPrefixSep  = []byte("_i")

)

举个简单的例子,假设表中有3行数据:

1,“TiDB”, “SQL Layer”, 10

2,“TiKV”, “KV Engine”, 20

3,“PD”, “Manager”, 30

那么首先每行数据都会映射为一个Key-Value pair,注意,这个表有一个Int类型的Primary Key,所以RowID的值即为这个Primary Key的值。假设这个表的Table ID 为10,其中Row的数据为:

t_r_10_1 --> ["TiDB", "SQL Layer", 10]

t_r_10_2 --> ["TiKV", "KV Engine", 20]

t_r_10_3 --> ["PD", "Manager", 30]

除了Primary Key之外,这个表还有一个Index,假设这个Index的ID为1,其数据为:

t_i_10_1_10_1 --> null

t_i_10_1_20_2 --> null

t_i_10_1_30_3 --> null

Database/Table 都有元信息,也就是其定义以及各项属性,这些信息也需要持久化,我们也将这些信息存储在TiKV中。每个Database/Table都被分配了一个唯一的ID,这个ID作为唯一标识,并且在编码为Key-Value时,这个ID都会编码到Key中,再加上m_前缀。这样可以构造出一个Key,Value中存储的是序列化后的元数据。除此之外,还有一个专门的Key-Value存储当前Schema信息的版本。TiDB使用Google F1的Online Schema变更算法,有一个后台线程在不断的检查TiKV上面存储的Schema版本是否发生变化,并且保证在一定时间内一定能够获取版本的变化(如果确实发生了变化)。

四. SQL 运算

用户的 SQL 请求会直接或者通过 Load Balancer 发送到 tidb-server,tidb-server 会解析 MySQL Protocol Packet,获取请求内容,然后做语法解析、查询计划制定和优化、执行查询计划获取和处理数据。数据全部存储在 TiKV 集群中,所以在这个过程中 tidb-server 需要和 tikv-server 交互,获取数据。最后 tidb-server 需要将查询结果返回给用户。

五. 

调度的流程

PD 不断的通过 Store 或者 Leader 的心跳包收集信息,获得整个集群的详细数据,并且根据这些信息以及调度策略生成调度操作序列,每次收到 Region Leader 发来的心跳包时,PD 都会检查是否有对这个 Region 待进行的操作,通过心跳包的回复消息,将需要进行的操作返回给 Region Leader,并在后面的心跳包中监测执行结果。

注意这里的操作只是给 Region Leader 的建议,并不保证一定能得到执行,具体是否会执行以及什么时候执行,由 Region Leader 自己根据当前自身状态来定。

信息收集

调度依赖于整个集群信息的收集,需要知道每个TiKV节点的状态以及每个Region的状态。TiKV集群会向PD汇报两类信息:

(1)每个TiKV节点会定期向PD汇报节点的整体信息。

      TiKV节点(Store)与PD之间存在心跳包,一方面PD通过心跳包检测每个Store是否存活,以及是否有新加入的Store;另一方面,心跳包中也会携带这个Store的状态信息,主要包括:

a)  总磁盘容量

b)  可用磁盘容量

c)  承载的Region数量

d)  数据写入速度

e) 发送/接受的Snapshot数量(Replica之间可能会通过Snapshot同步数据)

f)   是否过载

g)  标签信息(标签是否具备层级关系的一系列Tag)

(2)每个 Raft Group 的 Leader 会定期向 PD 汇报Region信息

     每个Raft Group 的 Leader 和 PD 之间存在心跳包,用于汇报这个Region的状态,主要包括下面几点信息:

a)   Leader的位置

b)   Followers的位置

c)   掉线Replica的个数

d)   数据写入/读取的速度

    PD 不断的通过这两类心跳消息收集整个集群的信息,再以这些信息作为决策的依据。

     除此之外,PD 还可以通过管理接口接受额外的信息,用来做更准确的决策。比如当某个 Store 的心跳包中断的时候,PD 并不能判断这个节点是临时失效还是永久失效,只能经过一段时间的等待(默认是 30 分钟),如果一直没有心跳包,就认为是 Store 已经下线,再决定需要将这个 Store 上面的 Region 都调度走。但是有的时候,是运维人员主动将某台机器下线,这个时候,可以通过 PD 的管理接口通知 PD 该 Store 不可用,PD 就可以马上判断需要将这个 Store 上面的 Region 都调度走。

调度策略

PD 收集以上信息后,还需要一些策略来制定具体的调度计划。

一个Region的Replica数量正确

   当PD通过某个Region Leader的心跳包发现这个Region的Replica的数量不满足要求时,需要通过Add/Remove Replica操作调整Replica数量。出现这种情况的可能原因是:

 A.某个节点掉线,上面的数据全部丢失,导致一些Region的Replica数量不足

 B.某个掉线节点又恢复服务,自动接入集群,这样之前已经弥补了Replica的Region的Replica数量过多,需要删除某个Replica

 C.管理员调整了副本策略,修改了max-replicas的配置

访问热点数量在 Store 之间均匀分配

    每个Store以及Region Leader 在上报信息时携带了当前访问负载的信息,比如Key的读取/写入速度。PD会检测出访问热点,且将其在节点之间分散开。

各个 Store 的存储空间占用大致相等

    每个 Store 启动的时候都会指定一个 Capacity 参数,表明这个 Store 的存储空间上限,PD 在做调度的时候,会考虑节点的存储空间剩余量。

控制调度速度,避免影响在线服务

    调度操作需要耗费 CPU、内存、磁盘 IO 以及网络带宽,我们需要避免对线上服务造成太大影响。PD 会对当前正在进行的操作数量进行控制,默认的速度控制是比较保守的,如果希望加快调度(比如已经停服务升级,增加新节点,希望尽快调度),那么可以通过 pd-ctl 手动加快调度速度。

支持手动下线节点

    当通过 pd-ctl 手动下线节点后,PD 会在一定的速率控制下,将节点上的数据调度走。当调度完成后,就会将这个节点置为下线状态。

一个 Raft Group 中的多个 Replica 不在同一个位置

 

以上内容为个人梳理总结于TiDB官网  https://www.pingcap.com/docs-cn/

以上是关于TiDB 整体架构及主要特性的主要内容,如果未能解决你的问题,请参考以下文章

TIDB 学习计划 --- 什么是分布式数据库和TIDB 整体架构

TIDB 架构及分布式协议Paxos和Raft对比

大数据大数据组件TiDB原理+实战篇

HBase-整体架构及读写原理

TOMCAT封神之旅-源码运行及整体架构

GopherChina 2017PingCAP Engineering VP 申砾《Go in TiDB》