LSMT存储引擎 | 青训营笔记

128 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的第8天

LSMT存储引擎介绍

1 LSMT历史

  • LSMT 是 Log-Structured Merge-Tree的缩写,由Patrick O ‘Neil etc.在1996年的论文,The Log-Structured Merge-Tree (LSM-Tree),提出。
  • 相较而言,B-Tree出现就早得多了,在1970年由Bayer, R.; McCreight,E.提出。
  • 早期的数据库系统一般都采用B-Tree家族作为索引,例如 MySQL。2000年后诞生的数据库大多采用LSMT 索引,例如Google BigTable,HBase,Canssandra等。

2.LSTM是什么

一言以蔽之,通过Append-only Write +择机 Compact来维护结构的索引树。

Snipaste_2022-08-09_18-03-31.jpg

存储引擎是什么

Snipaste_2022-08-09_18-08-53.jpg 以单机数据库MySQL为例,大致可以分为:

  • 计算层:计算层主要负责 SQL解析/查询优化/计划执行。
  • 存储层(存储引擎层):数据库著名的 ACID特性,在MySQL中全部强依赖于存储引擎。

ACID

  • Atomicity 原子性
  • Consistency(Correctness) 一致性
  • lsolation隔离性
  • Durability 持久性

除了保障ACID以外,存储引擎还要负责:

  • 屏蔽IO细节提供更好的抽象
  • 提供统计信息与Predicate Push Down能力

存储引擎不掌控IO细节,让操作系统接管,例如使用mmap,会有如下问题:

  • 落盘时机不确定造成的事务不安全
  • IO Stall
  • 错误处理繁琐
  • 无法完全发挥硬件性能

LSMT存储引擎的优势与实现

1.LSMT和B+Tree的异同

Snipaste_2022-08-09_18-15-26.jpg

  • 在B+Tree 中,数据插入是原地更新的
  • B+Tree在发生不平衡或者节点容量到达阈值后,必须立即进行分裂来平衡

Snipaste_2022-08-09_18-15-51.jpg

  • LSMT B+Tree 可以用统一模型描述
  • 从高层次的数据结构角度来看,二者没有本质的不同,可以互相转化
  • 工程实践上还是用LSMT来表示一个Append-only和Lazy Compact的索引树,B+Tree 来表示一个Inplace-Update和Instant Compact的索引树。
  • Append-only 和 Lazy Compact这两个特性更符合现代计算机设备的特性。

2.为什么采用LSMT模型

  • 'All problems in computer science can be solved by another level of indirection' ----From Butler Lampson
  • 在计算机存储乃至整个工程界都在利用Indirection处理资源的不对称性
  • 存储引擎面对的资源不对称性在不同时期是不同的

HDD时代

  • 顺序与随机操作性能不对称
  • 由于机械硬盘需要磁盘旋转和机械臂移动来进行读写,顺序写吞吐是随机读的25倍。 Snipaste_2022-08-09_18-20-11.jpg

SDD时代

  • 顺序写与随机写性能不对称
  • 由于SSD随机写会给主控带来GC压力,顺序写吞吐是随机写的6 倍。 Snipaste_2022-08-09_18-21-23.jpg

总结

  • HDD时代,顺序操作远快于随机操作
  • SSD时代,顺序写操作远快于随机写操作 这二者的共性是顺序写是一个对设备很友好的操作,LSMT符合这一点,而 B+Tree依赖原地更新,导致随机写。

3.LSMT存储引擎的实现,以RocksDB为例

  • RocksDB是一款十分流行的开源LSMT存储引擎,最早来自Facebook (Meta),应用于MyRocks,TiDB等数据库。
  • 在字节内部也有Abase,ByteKV,ByteNDB,Bytable 等用户。

Write实现

Snipaste_2022-08-09_18-24-49.jpg

  • RocksDB 写入流程主要有两个优化,批量WAL写入(继承自LevelDB)与并发MemTable更新
  • RocksDB在真正执行修改之前会先将变更写入WAL,WAL写成功则写入成功。

Snipaste_2022-08-09_18-26-16.jpg

  • 多个写入者会选出一个Leader,由这个Leader来一次性写入WAL,避免小lO。
  • 不要求WAL强制落盘(Sync)时,批量提交亦有好处,Leader可以同时唤醒其余Writer,降低了系统线程调度开销。

Snipaste_2022-08-09_18-28-00.jpg

  • 没有批量提交的话,只能链式唤醒。
  • 链式唤醒加大前台延迟。

Snipaste_2022-08-09_18-28-59.jpg

  • 写完WAL还要写MemTable。
  • RocksDB在继承LevelDB的基础上又添加了并发MemTable写入的优化。

Snipaste_2022-08-09_18-29-27.jpg

  • WAL一次性写入完成后,唤醒所有Writer并行写入 MemTable
  • 由最后一个完成 MemTable 写入的Writer执行收尾工作

Snapshot & SuperVision

Snipaste_2022-08-09_18-31-04.jpg

  • RocksDB的数据由3部分组成,MemTable/ lmmemTable / SST。持有这三部分数据并且提供快照功能的组件叫做SuperVersion。
  • MemTable 和SST的释放依赖于引用计数。对于读取来说,只要拿着SuperVersion,从MemTable 一级一级向下,就能查到记录。拿着SuperVersion不释放,等于是拿到了快照。
  • 如果所有读者都给SuperVersion的计数加1,读完后再减1,那么这个原子引用计数器就会成为热点。CPU在多核之间同步缓存是有开销的,核越多开销越大。
  • 为了让读操作更好的scale,RocksDB做了一个优化是Thread Local SuperVersionCache

Snipaste_2022-08-09_18-32-46.jpg

  • 没有Thread Local缓存时,读取操作要频繁Acquire和 Release SuperVersion
  • CPU 缓存不友好

Snipaste_2022-08-09_18-33-54.jpg

  • 有Thread Local缓存,读取只需要检查一下 SuperVersion并标记 ThreadLocal缓存正在使用即可
  • CPU 缓存友好

Get & BloomFilter

  • RocksDB的读取在大框架上和B+ Tree类似,就是层层向下。
  • 相对于B+Tree,LSMT点查需要访问的数据块更多。为了加速点查,一般LSMT引擎都会在SST中嵌入BloomFilter。

[1,10]表示这个索引块存储数据的区间在1 -10之间。查询2,就是顺着标绿色的块往下

Snipaste_2022-08-09_18-35-57.jpg

Compact-Level

Compact在 LSMT中是将Key区间有重叠或无效数据较多的SST进行合并,以此来加速读取或者回收空间。Compact策略可以分为两大类,Level和Tier。下图是Level策略

Snipaste_2022-08-09_18-36-44.jpg Level策略直接来自于LevelDB,也是RocksDB的默认策略。每一个层不允许有SST的Key区间重合。

Compact-Tier

Snipaste_2022-08-09_18-37-58.jpg Tier 策略允许LSMT每层有多个区间重合的SST

LSMT模型理论分析

Cloud-Native LSMT Storage Engine - HBase

  • RocksDB是单机存储引擎,那么现在都说云原生,HBase 比 RocksDB就更「云」一些SST直接存储于HDFS上。

  • 二者在理论存储模型上都是LSMT。 Snipaste_2022-08-09_18-39-07.jpg

  • 单机数据库的 ACID特性依赖于存储引擎

  • LSMT存储引擎的顺序写特性更适合现代计算机体系结构

  • LSMT和B+Tree可以用同一模型描述并互相转化

  • Level Compaction策略,降低了读放大和空间放大,增加了写放大

  • Tier Compaction策略,降低了写放大,增大了读放大和空间放大

  • 分布式KV存储,如 HBase,背后的理论模型与单机存储引擎RocksDB 一样都是LSMT