TiDB整体体系架构
- 水平扩容&缩容
- 金融机高可用
- 实时HTAP
- 云原生的分布式数据库
- 兼容MySQL 5.7 协议
- 前端(TiDB Server集群)Stateless
- 后端(TiKV集群、PD集群)Stateful(Raft)
TiDB Server
TiDB Server主要功能
-
处理客户端的连接
-
SQL语句的解析和编译
-
关系型数据与KV的转化
- region大小:96M~144M
-
SQL语句的执行
-
执行online DDL
- 不阻塞线上业务
-
垃圾回收 GC
-
热点小表缓存V6.0
- Cache table
TiDB Server架构
-
无状态,可横向扩展
-
利用LVS、HAProxy、F5提供统一接入地址,负载均衡
-
不存储数据,所有数据存在TiKV上
-
组件作用
- Protocol Layer| Parse | Compile:生成SQL语句的执行计划
- Executor|DistSQL|KV:执行计划的执行
- Transaction|KV:事务
- PD Client:与PD交互
- TiKV Client:与TiKV交互
- Schema load|worker|start job:处理online DDL
- memBuffer:缓存元数据、登录信息等
- cache table:小表缓存
SQL语句的解析和编译
解析
编译
- AST:Abstract Syntax Tree,抽象语法树
Key-Value转化
-
Key的形式:tablePrefix{TableID}_recordPrefixSep
-
如果声明的主键不是
INTEGER
数据类型,TiDB会为表创建非聚簇索引_tidb_rowid
:非聚簇索引的键
-
如果没有声明主键,TiDB会为表创建一个隐式主键
_tidb_rowid
:隐式键值
-
主键聚簇索引(Clustered):表的主键即为聚簇索引,存储一行至少需要一个键值对
-
主键非聚簇索引(Non-clustered):行数据的键由隐式分配的
_tidb_rowid
构成,主键在_tidb_rowid
上额外再建立索引,存储一行至少需要2个键值对
Region
SQL读写相关模块
- 复杂SQL走DistSQL,KV处理简单的请求(如点查)
在线DDL相关模块
-
DDL不会阻塞
-
同一时刻只能有一个TiDB Server可以做DDL操作
-
start job
把任务放到job queue
中,workers角色是owner时,才会去执行job,执行完放到history queue
,owner有任期,任期结束重新选举 -
schema load
在当workers成为owner后,缓存所有表的元数据,用于执行任务
GC机制与相关模块
-
safe_point
-
GC_life_time:数据的存活时间,默认10min
TiDB Server的缓存
-
缓存组成
-
SQL结果
-
线程缓存
-
元数据,统计信息,用户信息
-
-
缓存管理
- tidb_mem_quota_query:控制每条SQL占用缓存的大小
- oom-action:决定内存超过阀值后的操作
热点小表缓存
- 表的数据量不大:64M以下
- 只读表或者修改不频繁的表
- 表的访问很频繁
原理
-
tidb_table_cache_lease:缓存租约,单位秒,默认5
-
租约时间内,无法进行写操作
- 租约到期,数据过期
- 写操作不再被阻塞
- 读写直接到TiKV节点上执行
- 数据更新完毕,租约继续开启
应用
- 缓存表限制大小为64MB
- 适用于查询频繁、数据量不大、极少修改的场景
- 在租约(tidb_table_cache_lease)时间内,写操作会被阻塞
- 当租约(tidb_table_cache_lease)到期时,读性能会下降
- 不支持对缓存表直接做DDL操作,需要先关闭
- 对于表加载较慢或者极少修改的表,可以适当延长租约(tidb_table_cache_lease)保持读性能稳定
TiKV
主要功能
-
数据持久化
-
副本的强一致性和高可用性(分布式一致性)
-
MVCC(多版本并发控制)
-
分布式事务支持
-
Coprocessor(协同处理器)
- 提供算子下推能力,把计算工作下放到TiKV节点进行,节省带宽和IO,过滤/投影/计算
- 各组件作用
- rocksdbraft:存日志
- rocksdbkv:存数据
- Raft:高可用
- MVCC:多版本控制,读取控制
- Transation:支持事务
持久化
TiKV底层持久化使用了RocksDB,RocksDB针对Flash存储进行优化,延迟极小,使用LSM存储引擎
- 高性能的Key-Value数据库
- 完善的持久化机制,同时保证性能和安全性
- 良好的支持范围查询
- 为需要存储TB级别数据到本地FLASH或者RAM的应用服务器设计
- 针对存储在高速设备的中小键值进行优化,可以存储在FLASH或者直接存储在内存
- 性能随CPU数量线性提升,对多核系统友好
RocksDB写入
-
sync_log=true:会调用系统fsync直接将日志写入操作系统的磁盘中,而不会通过操作系统的内存
-
write_buffer_size:控制当memTable内存达到多少时将数据flush进immutable
-
immutable的存在可以防止memTable直接写磁盘时IO慢导致memTable写阻塞
-
writeStall:当immutable达到5个时,会限制memTable的写入速度,并记录日志,以保护RocksDB,可以通过优化存储性能或调大参数进行优化
-
Level 0就是immutable的复刻
-
磁盘上的是SST(Sort String Table)文件
-
当文件达到4个时,会进行compaction(压缩&排序),将文件存进下一层,查找时用二分查找法
-
写入时需要一次磁盘io,一次内存io,顺序写
-
对写友好,删除时只要写个delete即可,更新同理
RocksDB查询
- 查询时,先找对应文件里key的最小值和最大值,如果需要查找的key在这个范围,就用二分查找法查找数据,并且利用布隆过滤器查询数据是否存在
- 布隆过滤器判断数据不在就一定不在,判断数据在不一定在
Column Families
-
列簇(CF),数据分片技术
-
写入:write(cf1,id,name,age),write(cf2,id,addr,tell)
-
默认列簇为default
-
日志WAL不区分,多个列簇共享同一个日志文件
分布式事务
- 2PC
- prewrite
- commit
- 分成3个CF
- Deafult:存储超过255字节长度的数据
- Lock:存储锁信息
- Write:存储提交信息和小于255字节长度的数据
- 只给事务的第一行加锁,其他行的锁指向主锁
- 在写入之前,别人感知不到,叫做乐观锁;提前将锁写入TiKV节点中,叫做悲观锁。
MVCC
-
id=1,可读不可写
-
id=2,可读可写
-
id=4,可读不可写
Raft
- 初始化时,会写入同一个region,当region达到96MB时,会写入下一个region,存储的key是左闭右开区间
- 修改数据过程中,当某个 Region 的大小超过一定限制(默认是 144 MiB)后,TiKV 会将它分裂为两个或者更多个 Region,当某个 Region 因为大量的删除请求而变得太小时(默认是 20 MiB),TiKV 会将比较小的两个相邻 Region 合并为一个
Raft日志复制
过程
-
propose:将请求转成日志
-
append:将日志持久化至RocksDB raft中
-
replicate:leader将日志复制到其他follower节点
append:follower节点将日志持久化到RocksDB Raft
-
committed:超过50%节点告知leader节点已完成日志持久化
Raft层committed与应用程序事务的committed不一样,这里只是说Raft多副本协议的committed
-
apply:将数据真正写入到RocksDB KV中
应用程序committed成功
Raft Leader选举
-
term :时间段,没有固定长度
-
follower在特定情况下会变成candidate,candidate会发起投票,只要收到一半以上投票就成为leader,其他follower节点发现condidate节点的term比自己大,就投1票
-
heartbeat_time_interval:等待leader心跳的最长时间,超过时间收不到心跳就会发起选举
- TiDB参数:raft-heartbeat-ticks,默认10
-
election_timeout:无主状态下多长时间发起选举,实际上每个节点是随机时间random(100ms-300ms)
- TiDB参数:raft-election-timeout-ticks,不能小于raft-heartbeat-ticks
-
raft-base-tick-interval:raft每个ticks的大小,默认1s
数据的写入
数据的读取
ReadIndex Read
-
raftstore pool:日志线程池
-
apply pool:写入线程池
-
去PD查数据存放位置
-
读的时候发心跳确认是否为Leader
-
需要保证读取线性一致性
-
readIndex 记录当前 raft commit 的位置
-
applyIndex 记录当前 apply 的位置
-
读取时,需要记录readIndex,等待applyIndex执行到readIndex位置,才可以正常读取数据
Lease Read
也叫local read
- 记录一个开始时间,在一个时间周期内(election timeout)可以获取到follower节点的心跳,就可以认为一直是leader节点,就可以一直在该节点读取数据
Follwer Read
- follower向leader获取leader当前的commitIndex,然后follower等到applyIndex执行到commitIndex,才可以读取数据
leader
follower
-
有可能follower的apply速度比leader快,所以follower的读取可能比leader快,如下图
Coprocessor
- coprocessor有以下三种情景
- 执行物理算子,如:tableScan、indexScan、selection、limit、aggreate
- 分析统计信息 analyze
- 对表进行校验
Placement Driver
主要功能
-
整个机器TiKV的元数据存储
-
分配全局ID和事务ID
-
生成全局时间戳TSO
-
收集集群信息进行调度(TiKV、TiFlash按一定时间间隔向PD节点进行信息汇报)
-
提供label,支持高可用
-
提供TiDB Dashboard服务
架构
- 集成etcd raft存储数据
- TiDB机器大脑
- 元数据存储
- 全局时钟TSO
- Region调度
路由功能
- back off:region cache信息过旧,导致region转移导致路由失败
TSO
TimeStamp Oracle
概念
- TSO=physical time + logical time
- physical time:物理时间,取值是unix时钟
- logical time :逻辑时间,1ms分成262144个
- int64类型
分配
- 异步
- PD Client有批处理功能
时间窗口
- 将1段时间窗口的TSO放到缓存中,避免经常访问存储,解决性能问题
高可用
- 在获取TSO时,如果PD的leader节点宕机,另外的PD节点不管之前的TSO是什么,都会重新生成TSO
调度
总流程
信息收集
生成调度
- Balance
- Leader
- Region
- Hot Region
- 集群拓扑
- 缩容
- 故障恢复
- Region merge
执行调度
Label与高可用
Label配置
TiFlash
主要功能
-
异步复制
-
一致性读取
-
计算加速
- 列式存储提高分析查询效率
- 计算下推
-
业务隔离
-
TiKV承载OLTP业务
-
TiFlash承载OLAP业务
-
-
引擎智能选择
- TiDB Server通过SQL预测决定使用的引擎
架构
- TiFlash是只读的,靠异步复制
- TiFlash与TiKV也是一致性读取的,快照隔离级别
- QPS不高,小于50
异步复制
一致性读取
智能选择
TiDB数据库SQL执行流程
DML语句读流程概要
DML语句写流程概要
- 先读出来再修改
DDL流程概要
SQL的Parse与Compile
读取的执行
- snapshot:快照,只能查到当前时刻的数据
- UnifyRead Pool:查询线程池,按优先级到rocksdb kv查
- Cop task:算子下推到TiKV的任务
- Root task:TiDB Server的任务
写入的执行
- 将需要修改的数据提前读取到memBuffer中,再进行写入操作
- Scheduler:管理并发写入请求,使用latch管理
- Raftstore:将写请求转换为raft log
DDL的执行
- start job判断当前TiDB Server是否为owner,如果是,直接将任务交给workers执行,否则就将任务提交到TiKV的job queue中
- owner是轮询的,由PD节点控制
- 加索引的操作是单独放到add index queue中
TiDB数据库的HTAP概述
HTAP技术
传统的OLTP和OLAP方案
HTAP的要求
- 可拓展性
- 分布式事务
- 分布式存储
- 同时支持OLTP与OLAP
- 同时支持行存和列存
- OLTP与OLAP业务隔离
- 实时性
- 行存与列存数据实时同步
TiDB的HTAP架构
- TiFlash作为Raft Group的learner角色,只参与复制,不参与投票
TiDB的HTAP特性
- 行列混合
- 列存(TiFlash)支持基于主键的实时更新
- TiFlash作为列存副本
- OLTP与OLAP业务隔离
- 智能选择(CBO自动或者人工选择)
- MPP架构
MPP
- 大量数据的join聚合查询
- 所有MPP计算都在TiFlash节点内存中完成
- 目前只支持等值链接
- Enforce_mpp帮助验证是否可以使用MPP
每个TiFlash节点称之为MPP Worker
例子
先做过滤
数据交换
取hash
join操作
group by再做数据交换
聚合
结果
混合工作负载场景
流式计算场景
传统
TiDB
TiDB6.0新特性
Placement Rules in SQL
之前
- 跨地域部署的集群,无法本地访问
- 无法根据业务隔离资源
- 难以按照业务登记配置资源和副本数
之后
- 跨地域部署的集群,支持本地访问
- 根据业务隔离资源
- 按照业务等级配置资源和副本数
使用
步骤1
- 设计业务拓扑,为不同的TiKV实例设置标签
步骤2
- 创建PLACEMENT POLICY
步骤3
- 设定数据对象的PLACEMENT POLICY
应用
- 精细化数据放置,控制本地访问与跨区域访问
- 指定副本数,提供重要业务的可用性和数据可靠性
- 将业务按照等级、资源需求或者数据生命周期进行隔离
- 业务数据整合,降低运维成本与复杂度
小表缓存
参考TiKV 热点小表缓存
内存悲观锁
悲观锁
内存悲观锁
锁丢失
- 出现锁丢失后,事务会失败并回滚
使用
- 在线开启内存悲观锁
- set config tikv pessimistic-txn.pipelined=‘true’;
- set config tikv pessimistic-txn.in-memory=‘true’;
- 修改配置文件
应用
- 减少事务的延时
- 降低磁盘和网络带宽
- 降低TiKV的CPU消耗
- 锁丢失问题
Top SQL
之前
之后
使用
步骤1
- 选择需要观察负载的具体TiDB Server或TiKV实例
步骤2
- 观察Top 5类SQL
步骤3
- 查看某语句的执行情况:Call/sec(平均每秒请求数)、Scan Indexes/sec(平均每秒扫描索引数)等
作用
- 可视化地展示CPU开销最多的Top 5类SQL语句
- 支持制定TiDB Server及TiKV实例进行查询
- 支持统计所有正在执行的SQL语句
- 支持每秒请求数、平均延迟、查询计划等详细执行信息
TiDB Enterprise Manager(TiEM)
企业中TiDB集群管理的问题
- 数量增长
- 集群数量
- 节点数量
- 组件数量
- 工具数量
- 复杂度增长
- 配置参数复杂度
- 命令行复杂度
- 管理接口复杂
企业中TiDB集群管理的任务
- 部署集群
- 升级集群
- 参数管理
- 组件管理
- 备份恢复与高可用管理
- 集群监控与告警
- 集群日志收集
- 审计与安全
TiEM功能
- 一键部署集群&多套集群一站式管理
- 集群原地升级
- 参数管理
- 克隆集群&主备集群切换
TiDB Cloud
- TiDB Cloud是一个功能齐全的数据库即服务或DBaaS,是一个特殊的PaaS
TiDB的好处
- 分布式SQL数据库-多租户
- 混合工作负载-在同一个数据库中
- 事务型:基于行的数据
- 分析型:基于列的数据
- 弹性比例
- 缩小-减少节点
- 横向扩展-添加节点
- 基于“RAFT”的高可用性
- 每个数据段在3个可用区进行复制
多租户
- 什么是多租户?
- 在多租户架构中,应用程序的多个实例在共享环境中运行
- 每个租户在物理上都是集成的,但在逻辑上是分开的
- 一个软件实例为多个租户提供服务