作为一款分布式数据库,性能调优是 TiDB 中较为复杂且重要的部分。
下图展示 TiDB 各个模块地图,通过这张地图可以清晰展现 TiDB 如何处理一条 SQL。
TiDB 的【Server】模块会为 MySQL 客户端的每一个连接创建一个 session 并且分配一个 token。可以通过 Connection Count 这项监控来查看 TiDB 的连接数,通常建议单个 TiDB 的连接数不超过 500 个
经由这个 session 发送到 TiDB 的 SQL 会在【Parse】中被转化为能够被 TiDB 所理解的语法树。转化时间可通过监控【Executor/Parse Duration】查看,通常应该在 10ms 以内
TiDB 根据语法树生成物理执行计划,决定选择哪些索引或者算子进行计算,这个过程被称作【Compile】。执行时间可通过监控【Executor/Compile Duration】查看
生成的物理执行计划会在【Executor】中进行执行
如果是 DML 语句,TiDB 会将用户更新的内容先缓存在【Transaction】模块中,等到用户执行事务的 Commit 时再进行两阶段提交,将结果写入到 TiKV
对于复杂查询请求,TiDB 会通过 【DistSQL】模块并行地向 TiKV 的多个 region 发送查询请求,然后再按照执行计划中的流程计算出查询结果来
TiDB 发送给 TiKV 的各种请求耗时可以通过监控【KV Request/KV Request Duration 99 by type】查看
TiDB 采用两阶段提交的事务模型。为此需要向 PD 请求一个全局逻辑时间戳 TSO,用来表明事务的开始时间与提交时间。为了不给 PD 造成过多的请求压力,TiDB 通过单个线程一次为多个事务分配时间
事务在 channel 中等待的时间为监控【PD Client/PD TSO Wait Duration】
TiDB 向 PD 请求时间戳的网络请求耗时为监控【PD Client/PD TSO RPC duration】
参考 读写流程分析 一章
TiKV 的主要由 6 个模块构成。分别是 gRPC、Scheduler、raftstore、apply、storage-readpool 以及 coprocessor-readpool
gRPC 是 TiKV 所有请求的入口,他会将外界的请求转发给各个模块
scheduler 负责检测事务冲突,将复杂的事务操作转换为简单的 key-value 插入、删除,发送给 raftstore 线程
raftstore 负责执行 raft 日志复制,将数据复制给多个副本。当日志在多个副本上达成一致后,会发送给 apply 线程
apply 线程负责将 scheduler 线程的 key-value 操作写入 RocksDB。然后通知 gRPC 线程返回结果给客户端
storage-readpool 处理 kv get 以及 kv batch get 等简单的查询请求
coprocessor-readpool 处理复杂的范围查询以及表达式计算
TiKV 共持有两个 RocksDB 实例,一个用于 raftstore 线程记录 raft 日志与 raft 元信息。另一个用于记录用户写入的数据,以及 TiKV 事务中的锁信息
线程池调优请见 8.2.1 TiKV 线程池优化 章节
RocskDB 是一款优秀的开源单机存储引擎,负责将 TiDB 的数据存储在磁盘上。
RocksDB 的三种基本文件格式
Memtable 是一种内存文件数据系统,新数据会被写进 Memtable
读取数据如果 Memtable 没有,会访问 Block-Cache
Block-Cache 默认设置为系统总内存的 45%,单机多实例的情况下,按照实例个数分配
WAL Write Ahead Log 写操作先写入 logfile,再写入 Memtable
SST 在 Memtable 写满以后,将数据写入磁盘中的 SST 文件,对应 logfile 里的 log 会被安全删除。