目录
TiKV 持久化
TiKV架构及作用
RocksDB
RocksDB:查询
RocksDB:列簇
TiKV 分布式事务
TiKV Raft
Propose
Append
Replicate
Committed
Apply
Raft Leader选举
TiKV读写与Coprocessor
ReadIndex Read
Lease Read
Follower Read
Coprocessor
例题
TiKV 持久化
TiKV架构及作用
rocksdb:负责数据的落地,即持久化
rocksdb实例包括:
rocksdb raft:负责raft log日志的存取
rocksdb kv:负责键值对和图数据的存取
对与数据的分布式储存,有两种方式:Hash,Range
Hash:按照 Key做Hash,根据Hash值选择对应的存储节点
Range:按照Key分Range,某一段连续的 Key 都保存在一个存储节点上
raft group:raft gruop包括每个region和它的副本
TiKV的读写
rocksdb的读写:针对单个TiKV node的读写,是纵向的
raft共识算法的读写:针对多个TiKV node中的的region副本,是横向的
Raft协议通过Raft共识算法保证数据的分布式储存和数据的一致性,同时仅可能,将数据均衡的分布在集群的所有节点中
Coprocessor协调处理器
提供算子下推能力,使TiKV具有一部分过滤,聚合等SQL计算的能力,且是并行的
RocksDB
使用RSM Tree存储Key-Value的数据结构
与MySQL的B+ Tree相比,写入效率更高,但查询效率较低
RocksDB:写入
写友好型,具有顺序性,且比B+ Tree效率高
插入,删除先储存在内存,合并后写入磁盘
WAL 预写日志:保证写入的原子性和持久性,即使系统宕机也能进行故障恢复
参数symc_log=true:使写入信息直接写入磁盘WAL文件中,不经过内存
参数write_buffer_size:用于设置MemTable的大小;若超过设置的大小,数据则被转存至immutable,并开辟一个新的Memtable
immutable
设置immutab的目的在于进行磁盘IO时,作为SST文件的中间状态,不阻塞客户端写入;但只要有存在immutable,就开始向磁盘写入当写入操作过多,使immutable达到5个时,则触发rocksdb流控机制(write stall),即限制写入速度
ps:immutable不支持继续写入
磁盘内部运作机制
Level 0中的内容与immutable的内容相同,是immutable的转存,即immutable的副本
进升Level的条件
当到达4个(默认情况下)SST文件,就进行数据压缩(compaction),将4个SST文件合并为一个,并移至下一个Level(移至下一个Level数据量*10);在压缩过程中,会对Key进行重新排序
ps:写入需要一次内存IO,一次磁盘IO
RocksDB:查询
比B+ Tree慢
Block Cache
存储最近最长读取的数据
查询机制
只读最新,如果在更前Level中查到所需的Key,则不必向下一个Level查找
若key值为SST文件的Min和Max之间,使用二分法进行查找(若就是Min或Max直接返回)
若不在,则查找下一个SST文件
bloom Filter
用于判断元素是否在集合内
机制:
过滤器判断不在,一定不在
过滤器判断在,不一定在(有误判率)
RocksDB:列簇
列簇用于数据分片
使一个rocksdb有多个内存区域和多套SST文件,但WAL文件是所有列簇是共享的
写入时可以指定列簇,不指定则默认在default列簇
TiKV 分布式事务
begin:通过PD获取事务开始时间,即start_ts
提交的两阶段:
prewrite:将内存中的数据和将锁信息写入TiKV node中
commit:通过PD获取事务结束时间(或称提交时间),即commit_ts
向Write列簇写入提交信息
向Lock列簇写入解锁信息
其中:
当一个事务有多行时,只给事务的第一行添加主锁,其他行依附于该锁,即锁的指向
TiKV Node使用3个列簇存储有关事务的执行信息:
Default列簇:存储修改数据(大于255字节),且只存修改值(方便查询);Key=事务id+事务开始的时间戳
Lock列簇:存储锁信息,且只给事务的第一行添加主锁(即pk),其他行依附于该锁(锁的指向)
Write列簇:存储提交信息和一些小事务(小于255字节);Key=事务id+事务结束的时间戳,Value=事务的开始时间戳
简而言之,短数据存在Write列簇,长数据存在Default列簇
得出结论
prewrite阶段使用Default列簇(修改信息)和Lock列簇(锁信息)
commit阶段使用Lock列簇(解锁信息)和Write列簇(事务提交信息)
ps:解锁不是直接删除Lock列簇中的信息,而是添加一条解锁信息
根据锁的存在能否被其他会话感知,分为:
乐观事务:在提交时将锁信息写入TiKV node,使其他会话无法感知锁的存在
悲观事务:在提交前将锁信息写入TiKV node,使其他会话可以感知锁的存在
如上图所示,分布式事务在不同TiKV node中
@1,锁的指向,即表示该锁执行事务id=1的事务,即主锁的位置
若发生如下情况,事务的某一行在向Write列簇写入提交信息时宕机,也未添加解锁信息(如下图),TiDB如何恢复事务的执行
通过Lock列簇的写锁信息中锁的指向,找到指向的主锁,查找事务信息,继续未执行的步骤
以上图为例,通过查询事务id=1的执行,发现事务已完成,故接下来向Write列簇中添加事务提交信息并向Lock列簇中添加解锁信息、
MVCC 多版本并发控制
MVCC的运作原理:
修改时,生成所修改的region副本(同时向PD获取时间戳)并在其该副本中修改数据;在未提交修改时,则读取的数据来自未修改的版本即原本,使写不阻塞读
这些修改产生的副本,又叫快照(snapshot),即为GC垃圾清理的目标
补充:MVCC只在read commited和repeatable read两个隔离级别下工作,与隔离级别snapshot isolation无关
以上图为例,事务1完成了整个过程,而事务2未完成commit阶段
若此时,对事务2进行读取,结果为<1,Jack><2,Candy><4,Tony>
若此时,对事务2进行修改,则因锁而被阻塞
故在执行分布式事务的整个阶段,只阻塞写,不阻塞读
事务的读取
首先查询Write列簇,是否存在相应事务的提交信息
若查找到相应事务的提交信息(即以被持久化),则在相应的列簇(Default列簇)查询相应的事务信息(通过相应的Key=事务id+事务开始数据)
若Write列簇无相应事务的提交信息,且Lock列簇中存在锁信息,则无法修改该事务
对于MVCC是如何阻塞其他会话写入的的,需要三个指针(三个列簇分布一个)
如图(此时TSO=120),有会话写入事务id=1,在Write列簇中查找到事务id=1的提交信息(TSO=110),当在TSO=115时又添加了一把写锁(W)且为主锁(pk),没有解锁信息,写被阻塞
当有会话写入事务id=2(此时TSO=120),在Write列簇中查找到事务id=2的提交信息(TSO=110),且Lock列簇中没有关于事务id=2的锁,故写入未被阻塞
当有会话写入事务id=4(此时TSO=120),在Write列簇中查找到事务id=2的提交信息(TSO=110),当在TSO=115时又添加了一把写锁(W)且指向事务id=1的主锁,没有解锁信息,写被阻塞
TiKV Raft
raft group:region及其副本(上图以3副本为例)
Multi raft:由多个raft goup组成
raft log利用region ID+日志的顺序ID来作为唯一标识
所有客户端的读写流量都通过leader
Propose
操作被leader收到,leader准备同步并将写入请求转化为raft log的形式(Key=region id+log id)
Append
Append操作将raft log存入rocksdb实例中(rocksdb raft),进行(在leader中的)持久化
Replicate
leader将raft log复制给follower并在(follower中的)rocksdb中进行持久化(横向复制)
Committed
当大多数(超过一半,但不是所有的)follower将raft log持久化成功(返回append完成)
ps:但此时写入的数据未持久化(未在rocksdb kv中),只有当Apply操作后才写入rocksdb
整个阶段一共有两个Committed;一个是事务的提交,另一个是raft log的横向复制的完成
Apply
leader将raft log(rocksdb raft中)的操作apply至rocksdb kv中的数据,写入完成
ps:若大多数(超过一半的)follower没有持久化成功(Replicate),则日志不会被Apply
Raft Leader选举
leader周期性向follower发出含有统治信息的心跳(参数heartbeat time interval);若follower长时间收不到统治信息(参数election timeout),某个region将会转换为candidate(候选者),并发起投票重新选取leader
election timeout:控制收不到统治信息时,发起选举的阈值;一般用于初始化时进行选举(集群刚被创建))
heartbeat time interval:控制发出心跳的周期,当收不到心跳的时间且超过election timeout的阈值,发起选举;一般用于集群运行中
如图,当leader宕机,TiKV node 3长时间收不到心跳并率先达到阈值,自身转化为candidate,进入下一个term并发起选举
向其他region发起请求,进行投票;其他follower接收请求并同意比自己term大的请求(term=2<term=3)
如图,若碰巧所有Tikv node都转为candidate企图发起选取,election timeout参数将会初始为随机值,减小每个TiKV node达到阈值的记录;若还是有多个candidate重复该过程,整个过程发起了多次选取
election timeout:
raft-election-timeout-ticks:设置 election timeout有多少个相对时间单位(ticks,默认1s)
raft-base-tick-interval:设置每个相对时间单位(ticks)有多长时间
heartbeat time interval:
raft-heartbeat-ticks:设置 heartbeat time interval有多少个相对时间单位(ticks,默认1s)
raft-base-tick-interval:设置每个相对时间单位(ticks)有多长时间
假设raft-election-timeout-ticks=5,raft-base-tick-interval=1s,则election timeout=5*1=5s
ps:election timeout ticks不能小于heartbeat ticks
TiKV读写与Coprocessor
首先向PD获取所region的位置(哪一个leader,在哪一个TiKV上)
线程池:
raftstore pool:将数据被转化为raft log并持久化至rocksdb raft;向其他副本横向复制(propose,append,replicate,committed)
apply pool:将raft log应用于rocksdb kv(apply)
ReadIndex Read
本质上属于一种判断操作是否apply至rocksdb的机制,如下图
当某一会话提交操作(TSO=10:00),但其操作未apply至rocksdb;此时ReadIndex=1-95,ApplyIndex=1-92,rocksdb中的数据为1-92
当另一会话企图读取被修改的数据(TSO=10:05),此时raftstore pool将日志commit至1-97,但applypool将操作应用至1-93(该案例假设没有MVCC机制,若有则读取的是之前的数据即1-93);即将ReadIndex=1-97并阻塞commit,使其等待apply操作至1-97
当apply至1-95时,事务的commit完成
当apply至1-97时,即ApplyIndex等于ReadIndex,此时根据raft log的顺序性,事务1-95肯定已被持久化至rocksdb
总结:利用日志的顺序性,通过判断后面的日志是否已apply推断出要读取的日志是否apply
ReadIndex一定大于要读的raft log,当ApplyIndex等于ReadIndex时判断
Lease Read
若某个TiKV发出心跳,则该TiKV在发出心跳的heart time interval内均为leader,但heart time interval之后未发出心跳,此时不会立马发起选举,而要直到election timeout
例如leader发送心跳的周期为10ms,则在心跳发送后10ms内,则该TiKV node在这个时间段内一定为leader
Follower Read
在数据的读取中,leader及follower都会使用Reader Index机制绑定操作是否已应用于rocksdb;但是follower的往往会比leader更先得出结果(follower的apply速度比leader的快)
当收到读取请求时,follower向leader获取CommitIndex,当follower中的ApplyIndex大于向leader获取的CommitIndex,则说明修改以应用并读取数据
本质上是ReadIndex的变体,ReadIndex读取方式都在leader中执行,而Follower Read中CommitIndex在leader,但ApplyIndex在follower
Leader中:
Follower中:
Coprocessor
若不使用Coprocessor ,则数据将汇总在TiDB对网络带宽和CPU负载都有极高要求
而使用Coprocesser,TiDB的计算将下推至TiKV
当TiDB收到SQL语句,得出物理执行计划,推出可以由TiKV Coprocessor计算的部分
Coprocessor包括三大计算:
- 执行物理算子
- 分析数据
- 提交信息
下推的算子包括:索引扫,表扫,过滤等
例题
1.下列属于TiKV相关功能的是?(选4项)
A.系统参数和元数据信息的持久化
B.产生TSO
C.分布式事务实现
D.MVCC
E.生成物理执行计划
F.表统计信息的持久化
答案:A,C,D,F
解析:B:TSO由PD产生;E:由TiDB Server生成物理执行计划
注:元数据信息如用户名,密码,表名等
2关于TiKV数据持久化,下列说法不正确的是?
A.RocksDB有2个实例,分别用来持久化raft log和key value数据
B. RocksDB中WAL用来保证写不丢失
C.对于删除操作,只需要在原key value数据上标记已删除即可
D.RocksDB中,除了Level 0层的数据,其他Level都是单一排序持久化的
答案:C
解析:A:rocksdb包括两个实例,持久化raft log的rocksdb raft和持久化key value的rocksdb kv;B:WAL预习日志,直接将写入持久化至磁盘,即使系统宕机也能故障恢复;C:TiDB使用LSM Tree进行操作,LSM Tree是以插入为基础,如更新操作,也是在原有的那一行直接插入数据;D:Level 0的内容等于immutable的内容,而immutable有多个分批写入磁盘,没有进行排序,而其他Level均是有更低的Level压缩合并后按Key值排序而来