0%

TiDB概念

简介

TiDB 是PingCAP公司设计、研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式数据库产品,具备水平扩容或者缩容、实时 HTAP、云原生的分布式数据库、兼容 MySQL 5.7 协议和 MySQL 生态等重要特性。TiDB 适合高可用、强一致要求较高、数据规模较大等各种应用场景。

点击跳转官方文档

架构

tidb-architecture-v3.1

  • TiDB Server
    • SQL 层,对外暴露 MySQL 协议的连接 endpoint,负责接受客户端的连接,执行 SQL 解析和优化,最终生成分布式执行计划。
    • TiDB 层本身是无状态的,实践中可以启动多个 TiDB 实例,通过负载均衡组件(如 LVS、HAProxy 或 F5)对外提供统一的接入地址,客户端的连接可以均匀地分摊在多个 TiDB 实例上以达到负载均衡的效果。
    • TiDB Server 本身并不存储数据,只是解析 SQL,将实际的数据读取请求转发给底层的存储节点 TiKV(或 TiFlash)。
  • PD (Placement Driver) Server
    • 整个 TiDB 集群的元信息管理模块,负责存储每个 TiKV 节点实时的数据分布情况和集群的整体拓扑结构,提供 TiDB Dashboard 管控界面,并为分布式事务分配事务 ID。
    • PD 不仅存储元信息,同时还会根据 TiKV 节点实时上报的数据分布状态,下发数据调度命令给具体的 TiKV 节点,可以说是整个集群的“大脑”。
    • 此外,PD 本身也是由至少 3 个节点构成,拥有高可用的能力。建议部署奇数个 PD 节点。
  • 存储节点
    • TiKV Server
      • 负责存储数据,从外部看 TiKV 是一个分布式的提供事务的 Key-Value 存储引擎。
      • 存储数据的基本单位是 Region,每个 Region 负责存储一个 Key Range(从 StartKey 到 EndKey 的左闭右开区间)的数据,每个 TiKV 节点会负责多个 Region。
      • TiKV 的 API 在 KV 键值对层面提供对分布式事务的原生支持,默认提供了 SI (Snapshot Isolation) 的隔离级别,这也是 TiDB 在 SQL 层面支持分布式事务的核心。TiDB 的 SQL 层做完 SQL 解析后,会将 SQL 的执行计划转换为对 TiKV API 的实际调用。所以,数据都存储在 TiKV 中。另外,TiKV 中的数据都会自动维护多副本(默认为三副本),天然支持高可用和自动故障转移。
    • TiFlash
      • TiFlash 是一类特殊的存储节点。和普通 TiKV 节点不一样的是,在 TiFlash 内部,数据是以列式的形式进行存储,主要的功能是为分析型的场景加速。

图片19

TiKV Server-存储

TiKV负责行数据存储,使用key-value的存储模型。

基于Facebook开源的RocksDB,进行单机KV存储,因此可以将TiKV看成一个巨大且有序的KV Map。

Key-Value

TiDB 会为每个表分配一个表 ID,用 TableID表示。

TiDB 会为表中每行数据分配一个行 ID,用 RowID 表示,如果某个表有整数型的主键,TiDB 会使用主键的值当做这一行数据的行 ID。

每行数据按照以下结构编码成键值对:

1
2
3
4
5
6
7
8
9
10
Key:   tablePrefix{TableID}_recordPrefixSep{RowID}
Value: [col1, col2, col3, col4]

-- 主键和唯一索引
Key: tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
Value: RowID

-- 非唯一的普通二级索引
Key: tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue_{RowID}
Value: null

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 表结构
CREATE TABLE User (
ID int,
Name varchar(20),
Role varchar(20),
Age int,
PRIMARY KEY (ID),
KEY idxAge (Age)
);
-- 数据
1, "TiDB", "SQL Layer", 10
2, "TiKV", "KV Engine", 20
3, "PD", "Manager", 30

-- 假设该表的 TableID 为 10,则其存储在 TiKV 上的表数据为:
t10_r1 --> ["TiDB", "SQL Layer", 10]
t10_r2 --> ["TiKV", "KV Engine", 20]
t10_r3 --> ["PD", "Manager", 30]

-- 除了主键外,该表还有一个非唯一的普通二级索引 idxAge,假设这个索引的 IndexID 为 1,则其存储在 TiKV 上的索引数据为:
t10_i1_10_1 --> null
t10_i1_20_2 --> null
t10_i1_30_3 --> null

Region

为了实现水平扩展,将数据分散到多台机器上,TiKV使用range方式切分数据,将整个Key-Value空间分成很多段,每个段叫做一个region。

图片23

每个region默认不超过96MB,使用[startkey,endkey)这样左闭右开的区间来描述数据。

TiKV会以region为单位,将数据分散到多个节点上,尽量保证每个节点上region数量差不多。PD负责将region均匀的调度到所有节点上,且维护region的路由信息,方便查询。

ac18c4b8106d41a79ceab42bf87ffe64

以region为单位做raft数据复制和成员管理。

一个region会有多个副本,多个replica组成一个raft group,其中一个replica作为这个raft group的leader,其他replica作为follower。

tidb-storage-3

replica之间通过raft协议保持数据一致性,默认所有的复写操作都在leader上进行,写操作由leader复制给follower。

图片21

以 Region 为单位做数据的分散和复制,TiKV 就成为了一个分布式的具备一定容灾能力的 KeyValue 系统,不用再担心数据存不下,或者是磁盘故障丢失数据的问题。

MVCC

TiKV 的 MVCC 实现是通过在 Key 后面添加版本号来实现。

没有MVCC的KV数据如下:

1
2
3
4
Key1 -> Value
Key2 -> Value
……
KeyN -> Value

有MVCC:

1
2
3
4
5
6
7
8
9
10
11
12
Key1_Version3 -> Value
Key1_Version2 -> Value
Key1_Version1 -> Value
……
Key2_Version4 -> Value
Key2_Version3 -> Value
Key2_Version2 -> Value
Key2_Version1 -> Value
……
KeyN_Version2 -> Value
KeyN_Version1 -> Value
……

对于同一个 Key 的多个版本,版本号较大的会被放在前面,版本号小的会被放在后面。

这样当用户通过一个 Key + Version 来获取 Value 的时候,可以通过 Key 和 Version 构造出 MVCC 的 Key,也就是 Key_Version。

也可以直接通过 RocksDB 的 SeekPrefix(Key_Version) API,定位到第一个大于等于这个 Key_Version 的位置。

TiDB Server-SQL层

TiDB 的 SQL 层,即 TiDB Server,负责将 SQL 翻译成 Key-Value 操作,将其转发给共用的分布式 Key-Value 存储层 TiKV,然后组装 TiKV 返回的结果,最终将查询结果返回给客户端。

这一层的节点都是无状态的,节点本身并不存储数据,节点之间完全对等。

分布式 SQL 运算

TiDB Server通过RPC从TiKV读取数据,因此为了减少不必要的RPC开销,会将条件带入TiKV查询计算,各个TiKV节点返回运算后的数据,统一处理,提升性能。

tidb-computing-dist-sql-flow

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

tidb-computing-tidb-sql-layer

PD-调度

PD(Placement Driver) 是 TiDB 集群的管理模块,同时也负责集群数据的实时调度。

信息收集

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

  • TiKV 节点信息:TiKV 节点 (Store) 与 PD 之间存在心跳包,一方面 PD 通过心跳包检测每个 Store 是否存活,以及是否有新加入的 Store;另一方面,心跳包中也会携带这个 Store 的状态信息
    • 总磁盘容量
    • 可用磁盘容量
    • 承载的 Region 数量
    • 数据写入/读取速度
    • 发送/接受的 Snapshot 数量(副本之间可能会通过 Snapshot 同步数据)
    • 是否过载
    • labels 标签信息
  • Region 信息:每个 Raft Group 的 Leader 和 PD 之间存在心跳包,用于汇报这个 Region 的状态
    • Leader 的位置
    • Followers 的位置
    • 掉线副本的个数
    • 数据写入/读取的速度

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