LSM Tree的读写过程
- HBase、LevelDB,rocksDB(是一个引擎)底层的数据结构是LSM Tree
- 适合写多读少的场景,都是追加写入内存中的MemTable,写入一条删除(或修改)标记,而不用去访问实际的数据,从而大大提高写的速度
- 追加顺序写(innodb的页是随机的)
- sst和memTable有序是为了compact,范围查询,key 的有序性可以让我们对sst其进行增量编码、indexblock的页目录
写操作
MemTable: 是一个内存缓冲区,跳表实现,数据有序,append操作到这个内存,默认大小64M,期间有预写操作,每次刷盘都会在 L0 层上产生一个新的 SST 文件(rocksDB中默认L0上有四个SST,超过就compact)
SST: 默认 SST 文件大小:64MB,其中有多个block(4k)存数据,有布隆过滤器和indexBlock,类比innodb中的页目录
因为sst中会有许多操作不同,但是key相同的数据,为了避免空间放大和读放大(读多个sst),有compact操作,就是某一层的sst数量超过阈值,和下一层有相同key范围的sst进行归并排序,通过 K 路归并算法逐步合并多个 SST 文件
读操作
以下是查找步骤:
检索 MemTable。
检索不可变 MemTables。
搜索最近 flush 过的 L0 层中的所有 SST 文件。
对于 L1 层及以下层级,首先找到可能包含该 key 的单个 SST 文件,然后在文件内进行搜索。
块索引在 SSTable 文件被打开时加载到内存。在查找时首先从内存中的索引二分查找找到块,然后一次磁盘寻道即可读取到相应的块。只加载索引,再找block
搜索 SST 文件涉及:
(可选)探测布隆过滤器。
查找 index 来找到可能包含这个 key 的 block 所在位置。
读取 block 文件并尝试在其中找到 key。
目前的实现
newSQL和NoSQL和传统sql
1. 前两个的出现
1. 都是为了解决传统sql的单机限制,如容量和自动恢复和分布式事务,如mycat中间件只能解决分片和容量,解决不了自动恢复,分布式事务还要引入seata
2. mysql支持的是异步和半同步复制,宕机的时候部分数据不一致
3. 刷盘上面,分为,mysql(传统)用的是B+树结构,即刷的是对应的页(磁盘的页和内存的页的格式相同),还有就是tidb是kv的追加------其实这么总结实际上是因为只了解innodb和rocksDB(这个只是区别,不是解决的问题)
2. new和no的区别:
nosql如mongoDB
NewSQL仍然采用关系型数据模型,如TiDB完全适配Mysql,在下层会把表结构转化为kv结构,即表格和数据行的模型。这意味着数据结构必须遵循预定义的表格模式和关系。而NoSQL则采用了不同的数据模型,如键值对、文档、列族和图形等。NoSQL的数据模型更加灵活,适应了不同类型和结构的数据存储需求。
NewSQL对数据一致性要求更高(但是实际上MongoDB后续也支持分布式事务),追求强一致性(ACID特性)。这意味着在数据写入与读取过程中,数据一定会达到一致的状态。然而,NoSQL对一致性要求相对较低,更注重可用性和性能,可能会出现数据在不同节点间的延迟和冲突。
TiDB架构(newSQL)
Raft如何参与TiDB的分布式存储
- TiDB 的数据在 TiKV 中是按照 **Key 的范围(Range)划分的。每个 Region 负责存储 连续的一段 Key,大小96MB
- 每一个region集群都是一个raft group,即有主节点提供写和写入时大部分节点的确认,选举也是发生在一个region集群里
- 为了避免脑裂,region的个数一般是奇数,能保证总有一个区能选出leader,另一个区无效,否则偶数的话,正好平分,就两个区都不可用
- 不同的leader在不同的节点,这样能负载写入的压力
参考:
https://cloud.tencent.com/developer/article/2329992 一文科普 RocksDB 工作原理
https://cloud.tencent.com/developer/article/2180532 LSM-tree 日志结构合并树详解
https://www.infoq.cn/news/how-to-build-a-distributed-database TiDB作者文章
https://zhuanlan.zhihu.com/p/491638316 理解raft文章
https://book.tidb.io/session4/chapter4/two-dc-raft.html 细节如何划分raft的数量