TiDB介绍
什么是TiDB
TiDB 是一个分布式的 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景(on-line transaction processing,联机事务处理)还适合 OLAP 场景(On-Line Analytical Processing,联机分析处理)的混合数据库。
NewSQL
NewSQL 是一类诞生于互联网大规模数据和高并发场景的数据库技术,其核心目标是同时兼顾传统关系型数据库的强事务性(ACID)、SQL 兼容性,以及 NoSQL 的分布式扩展性。
OLTP
- 支持短时间内大量并发的事务操作(增删改查)能力,每个操作涉及的数据量都很小(比如几十到几百字节)
- 支持事务的强一致性
OLAP
- 偏向于复杂的只读查询,读取海量数据进行分析计算
开发语言
TiDB整个项目分为两层,TiDB 作为 SQL 层,采用 Go 语言开发, TiKV 作为下边的分布式存储引擎,采用 Rust 语言开发。
对比传统单机数据库的优势
- 纯分布式架构,拥有良好的扩展性,支持弹性的扩缩容
- 支持 SQL,对外暴露 MySQL 的网络协议,并兼容大多数 MySQL 的语法,在大多数场景下可以直接替换 MySQL
- 默认支持高可用,在少数副本失效的情况下,数据库本身能够自动进行数据修复和故障转移,对业务透明
- 支持 ACID 事务,对于一些有强一致需求的场景友好,例如:银行转账
- 具有丰富的工具链生态,覆盖数据迁移、同步、备份等多种场景
架构设计
架构图
TiDB Server
TiDB Server 负责接收 SQL 请求,处理 SQL 相关的逻辑并通过 PD Server找到存储计算所需数据的TiKV 地址,与 TiKV 交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(如LVS、HAProxy 或 F5)对外提供统一的接入地址
PD Server
Placement Driver (简称 PD) 是整个集群的管理模块,其主要工作有三个:
- 存储集群的元信息(某个 Key 存储在哪个 TiKV 节点);
- 对 TiKV 集群进行调度和负载均衡(如数据的迁移、Raft group leader 的迁移等);
- 分配全局唯一且递增的事务 ID。
PD 通过 Raft 协议保证数据的安全性。Raft 的leader server 负责处理所有操作,其余的 PD server 仅用于保证高可用。建议部署奇数个 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 为单位进行调度
TiSpark
TiSpark 作为TiDB中解决用户复杂 OLAP 需求的主要组件,将 Spark SQL 直接运行在 TiDB 存储层上,同时融合 TiKV 分布式集群的优势,并融入大数据社区生态。至此,TiDB可以通过一套系统,同时支持OLTP与OLAP,免除用户数据同步的烦恼
TiDB Operator
TiDB Operator 提供在主流云基础设施(Kubernetes)上部署管理 TiDB 集群的能力。它结合云原生社区的容器编排最佳实践与 TiDB 的专业运维知识,集成一键部署、多集群混部、自动运维、故障自愈等能力,极大地降低了用户使用和管理 TiDB 的门槛与成本
核心特性:水平扩展与高可用
高度兼容 MySQL
大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。对于用户使用的时候,可以透明地从MySQL切换到TiDB 中,只是“新MySQL”的后端是存储“无限的”,不再受制于Local的磁盘容量。在运维使用时也可以将TiDB当做一个从库挂到MySQL主从架构中。
分布式事务
TiDB 100% 支持标准的 ACID 事务。
一站式 HTAP 解决方案
HTAP: Hybrid Transactional/Analytical Processing
TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP 解决方案,一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程。
云原生 SQL 数据库
TiDB 是为云而设计的数据库,支持公有云、私有云和混合云,配合 TiDB Operator 项目 可实现自动化运维,使部署、配置和维护变得十分简单。
水平弹性扩展
通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。
水平扩展
无限水平扩展是 TiDB 的一大特点,这里说的水平扩展包括两方面:计算能力(TiDB)和存储能力(TiKV)。
- 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 是无状态的,推荐至少部署两个实例,前端通过负载均衡组件对外提供服务。当单个实例失效时,会影响正在这个实例上进行的 Session,从应用的角度看,会出现单次请求失败的情况,重新连接后即可继续获得服务。单个实例失效后,可以重启这个实例或者部署一个新的实例。
PD
PD 是一个集群,通过 Raft 协议保持数据的一致性,单个实例失效时,如果这个实例不是 Raft 的 leader,那么服务完全不受影响;如果这个实例是 Raft 的 leader,会重新选出新的 Raft leader,自动恢复服务。PD 在选举的过程中无法对外提供服务,这个时间大约是3秒钟。推荐至少部署三个 PD 实例,单个实例失效后,重启这个实例或者添加新的实例。
TiKV
TiKV 是一个集群,通过 Raft 协议保持数据的一致性(副本数量可配置,默认保存三副本),并通过 PD 做负载均衡调度。单个节点失效时,会影响这个节点上存储的所有 Region。对于 Region 中的 Leader 节点,会中断服务,等待重新选举;对于 Region 中的 Follower 节点,不会影响服务。当某个 TiKV 节点失效,并且在一段时间内(默认 30 分钟)无法恢复,PD 会将其上的数据迁移到其他的 TiKV 节点上。
存储和计算
存储能力-TiKV-LSM
TiKV Server通常是3+的,TiDB每份数据缺省为3副本,这一点与HDFS有些相似,但是通过Raft协议进行数据复制,TiKV Server上的数据的是以Region为单位进行,由PD Server集群进行统一调度,类似HBASE的Region调度。
TiKV集群存储的数据格式是KV的,在TiDB中,并不是将数据直接存储在 HDD/SSD中,而是通过RocksDB实现了TB级别的本地化存储方案,着重提的一点是:RocksDB和HBASE一样,都是通过 LSM树作为存储方案,避免了B+树叶子节点膨胀带来的大量随机读写。从而提升了整体的吞吐量。
计算能力-TiDB Server
TiDB Server本身是无状态的,意味着当计算能力成为瓶颈的时候,可以直接扩容机器,对用户是透明的。理论上TiDB Server的数量并没有上限限制。
性能
1)基于CBO(Cost-Based Optimization)优化器:使用最小代价的物理计划优化算法,率先在Oracle7上使用,现在主流数据库都已经采用了CBO优化器
2)向量化:利用SIMD指令集,充分发挥CPU的处理能力,一些新型的分布式数据库也均已采用全面向量化,如doris,clickhouse等
3)协处理:将计算尽量靠近存储节点,TiFlash 和TIKV同时都拥有协处理的能力,类似于谓词下推,可以将计算下推到TiFlash和TIKV,从而利用分布式计算能力,且减少RPC的调用次数以及传输的数据量,最终提高计算性能
4)行存(TIKV)和列存(TiFlash)同时存在,并且能智能选择最优的执行计划(需要保证表的健康度)
注意事项
1)如果不Order by ,每次返回的数据顺序都不一致
在单机数据库中由于数据都存储在一台服务器上,有些数据库(尤其是 MySQL InnoDB 存储引擎)还会按照主键或索引的顺序进行结果集的输出,所以每次查询返回的数据顺序相对稳定。
而TiDB 是分布式数据库,数据被存储在多台服务器上,多份数据返回的时间先后并不固定。另外 TiDB 层不缓存数据页,因此不含 order by 的 SQL 语句查询出来的结果集的数据顺序无法保证一致。
2)自增列不能保证连续
TiDB中自增列只保证自增且唯一,并不保证连续
TiDB目前采用批量分配的方式,所以如果在多台 TiDB 上同时插入数据,分配的自增 ID 会不连续。当多个线程并发往不同的 tidb-server 插入数据的时候,有可能会出现后插入的数据自增 ID 小的情况。
TiDB 实现自增 ID 的原理是每个 tidb-server 实例缓存一段 ID 值用于分配(目前会缓存 30000 个 ID),用完这段值再去取下一段。在集群中有多个 tidb-server 时,人为向自增列写入值之后,可能会导致 TiDB 分配自增值冲突而报 “Duplicate entry” 错误。
3)表的健康度要关注
TIDB采用CBO优化器来生成物理执行计划,当某个表的健康度降低的时候,会导致CBO执行器无法准确判断走哪个索引的代价更小,从而导致选择错误的索引,而导致查询性能较低。
通过 SHOW STATS_HEALTHY 可以查看表的统计信息健康度,并粗略估计表上统计信息的准确度。当 modify_count >= row_count 时,健康度为 0;当 modify_count < row_count 时,健康度为 (1 - modify_count/row_count) * 100。
健康度越高,执行器选择正确的索引的成功率越高。
TiDB会自动收集表信息,可以通过下面语句查询TIDB执行收集信息的时间和阀值。
show variables like '%analyze%'
tidb_auto_analyze_ratio 默认为0.5,表示健康度低于50的时候在tidb_auto_analyze_start_time 和 tidb_aotu_analyze_end_time的时间范围内会自动执行analyze table table_name 来收集信息。(ps: +0000表示时区,+0800是东八区)
4)注意谓词下推,很多函数不支持
5)事务超时
含 DML 语句的事务,除了受 tikv_gc_life_time 限制之外,还受到另外一个参数 max-txn-time-use 的影响,这个参数位于 tidb-server 的配置文件 tidb.toml 中,用于控制单个事务允许的最大执行时间。该参数的默认值为 590(秒),需要注意必须控制该参数的值小于 tikv_gc_life_time 的值。
如 insert into t2 select * from t1的 SQL 语句,即使执行时间没有达到 tikv_gc_life_time 限制,但超过了 max-txn-time-use 的限制,会由于超时而回滚。
6)OOM问题
TIKV由于是KV结构存储的,不具备Join能力,如果查询语句中有关联表没有Tiflash,则必须要将TIKV中的所有数据都拉取到TiDB节点再进行处理,此时极易产生OOM。应当尽量避免此类情况产生,也可以通过设置SQL内存的方式来增大内存使用量。
例如:
配置整条 SQL 的内存使用阈值为 8GB:
SET tidb_mem_quota_query = 8 << 30;
配置整条 SQL 的内存使用阈值为 8MB:
SET tidb_mem_quota_query = 8 << 20;
7)Index Merge 只支持 or ,不支持 and
TiDB 4.0之后开始支持Index Merge,但是目前6.2版本也支持or的操作,对于and的查询操作仍然是不支持的。那就意味着在创建索引的时候不能向MySQL那样创建多个单独索引,而是需要根据实际使用的场景建立联合索引(这点尤为重要)。
TIDB的部署
1)因 TiDB 和 PD 对磁盘 IO 要求不高,所以只需要普通磁盘即可。
2)TiKV 对磁盘 IO 要求较高。TiKV 硬盘大小建议不超过 500G,以防止硬盘损害时,数据恢复耗时过长。整个 TiDB 架构是面向未来、面向海量数据高并发场景,底层存储技术(如数据定位 seek)都是针对当前主流的 SSD 进行设计和优化的,不会对传统的 SATA/SAS 机械硬盘再进行优化。
3)部署工具使用了 TiDB-Ansible。TiDB-Ansible 是 PingCap 基于 Ansible playbook 功能编写了一个集群部署工具叫 TiDB-Ansible。使用该工具可以快速部署一个完整的 TiDB 集群(包括 PD、TiDB、TiKV 和集群监控模块)。