前面的文章我们学习了TiDB的整体架构,也重点描述了TiKV组件,包括TiKV中的Raft复制、分布式事务、持久化存储等,本篇重点描述TiDB Server组件。
作为SQL执行引擎层,TiDB Server允许客户端使用标准的MySQL协议(当前已经兼容MySQL 8.0版本)连接数据库集群,负责对SQL进行解析、编译与执行并转换为对底层TiKV的键值处理。TiDB Server是无状态的,本身并不会持久化数据。每个TiDB Server节点都是对等的,可以很方便的进行扩缩容操作。在生产环境中,为了实现每个TiDB Server节点可以均衡使用,推荐借助负载均衡组件如硬件F5或软件haproxy来分发连接。
TiDB Server的架构可以用上图来表示,具体模块可以分为以下几部分来概述:
(1)SQL接收、解析及编译模块。包括图中的Protocol Layer、Parse、Compile。Protocol接收用户SQL,Parse解析语句,Compile编译语句,通过这几个模块将客户端SQL语句变成一个最终的执行计划。
(2)SQL语句执行模块。包括图中的Executor、DistSQL、Transaction、KV。其中Executor、DistSQL和KV主要负责分批的执行SQL语句,其中DistSQL用于处理复杂语句而KV用于处理点查询;Transaction和KV负责跟事务有关的执行如写操作。
(3)PD和TiKV的客户端模块。包括图中的PD Client及TiKV Client。其中PD Client负责和PD交互,比如从PD中批量获取TSO;TiKV Client负责和TiKV交互,将所有SQL请求转化为对TiKV的键值处理。
(4)在线DDL模块。包括图中的schema load、worker及start
job,关于这几个组件的作用我们在文章 了解TiDB中的DML/DDL执行流程
(qq.com) 已经有相关介绍。
(5)缓存模块。包括图中的memBuffer及cache table。memBuffer用于缓存最新读取的数据及元数据,包括一些登录认证信息、统计信息等;cache table是TiDB 6.0版本中引入的热点缓存表功能。
(6)垃圾回收模块。TiDB中所有的增删改操作都转换为插入操作,正常情况下TiDB集群中保存了数据的多个不同的版本,为了避免数据膨胀严重,需要有一个专门的垃圾回收模块。
下面具体介绍几个重点模块具体执行的细节。
一. SQL解析及编译
SQL语句的解析由Parser模块处理,它主要分为词法解析(lex)和语法解析(yacc)两个动作。词法解析是将传入的SQL语句拆分为一个个的token,包括关键字、列名、表名、条件等;语法解析会生成树型结构的AST语法树,比如图中的列名下面有name、age、address。
编译过程由Compiler模块执行,它拿到解析生成的AST之后,首先做一个合法性验证(比如读取缓存中的元数据判断表是否存在),其次进行逻辑优化(基于关系代数等价交换规则进行逻辑变化,如列裁剪、谓词下推等),最后进行物理优化(比如结合数据分布、统计信息判断应该走索引还是全表扫描)。经过上述步骤后,生成最终的物理执行计划。
二. 关系模型与KV的转换
TiDB对外呈现的是一个标准的关系型数据库,底层存储则是基于RocksDB的键值存储,这就涉及到关系模型是如何映射到KV存储的问题。针对于有主键的表,数据库会将tablePrefix{TableID}_recordPrefixSep{RowID} 映射为Key,将主键以外的字段作为Value。如果创建的表是聚簇表,这里的RowID就对应主键(关于聚簇表和非聚簇表本文不作详细说明)。因此,假设一张聚簇表的数据(其中编号是主键字段)如下图所示,
那么它的Key和Value映射如下,
另外,唯一索引和普通索引对应的Key和Value也会有所不同。
三. TiDB Server的缓存
TiDB Server的缓存,即memBuffer,主要存放几部分内容,包括:
(1)SQL结果。例如一张多表关联的语句,多张表的数据存在于不同的TiKV节点,需要将相关的数据读取到TiDB Server节点的缓存中进行关联操作。事务操作中要更新的数据也会先读取到缓存中进行修改。
(2)线程缓存。不同组件的线程都有各自的线程池缓存。
(3)元数据,统计信息。SQL解析、编译及优化过程中涉及到的元数据和统计信息,以及用户登录认证信息。
关于TiDB Server的缓存管理,有两个重要的参数:tidb_mem_quota_query和tidb_mem_oom_action。tidb_mem_quota_query表示每个查询默认使用的缓存大小,如果不希望单个查询语句占用缓存过大,可以适当的调小这个参数值。如果查询语句占用的内存超过tidb_mem_quota_query,则由tidb_mem_oom_action决定接下来的行为是中断语句返回错误还是记录日志。下图为TiDB 7.x版本中两个参数的默认值,它们表示当单条SQL语句占用的缓存大小超过1G时可能会中断报错。需要注意的是,官网描述tidb_mem_oom_action变量控制当单个查询使用的内存超过tidb_mem_quota_query限制且不能再利用临时磁盘时TiDB所采取的操作,因此这个参数控制本身可能并不太准确。
TiDB Server中的另一个缓存功能是cache table,关于cache table的描述,具体可参考文章 了解TiDB 6.0特性之热点小表缓存 (qq.com)