RUM 猜想说的是,对任何数据结构来说,在 Read Overhead(读)、Update Overhead(写) 和 Memory or Storage Overhead(存储) 中,同时优化两项时,需要以另一项劣化作为代价。
B+树写入问题:
- 写放大
- 存储不连续,链表结构,逻辑连续
- 填充因子,预留空间,很难拿捏
LSM-Tree
系统接收到写操作后会记录日志(Tablet Log)并将数据写入内存(Memtable),这时写操作就可以返回成功了。而在系统接收到读操作时,会在内存和磁盘文件中查找对应的数据。
LSM 是分成三步完成了数据的落盘:
- 第一步已经说过了,就是写入 Memtable,同时记录 Tablet Log;
- 当 Memtable 的数据达到一定阈值后,系统会把其冻结并将其中的数据顺序写入磁盘上的有序文件(Sorted String Table,SSTable)中,这个操作被称为 Flush;当然,执行这个动作的同时,系统会同步创建一个新的 Memtable,处理写入请求。
- 根据第二步的处理逻辑,Memtable 会周期性地产生 SSTable。当满足一定的规则时,这些 SSTable 会被合并为一个大的 SSTable。这个操作称为 Compact。
Leveled compact策略,它的设计核心就是将数据分成一系列 Key 互不重叠且固定大小的 SSTable 文件,并分层(Level)管理。同时,系统记录每个 SSTable 文件存储的 Key 的范围。Leveled 策略最先在 LevelDB 中使用,也因此得名。
详细过程:
- 同上第一步,写入L0层,保证写盘速度。
- 通常系统会通过指定 SSTable 数量和大小的方式控制每一个层的数据总量。当 L0 超过预定文件数量,就会触发 L0 向 L1 的 Compact。因为在 L0 的 SSTable 中 Key 是交叉的,所以要读取 L0 的所有 SSTable,写入 L1,完成后再删除 L0 文件。从 L1 开始,SSTable 都是保证 Key 不重叠的。
- 随着 L1 层数据量的增多,SSTable 可能会重新划分边界,目的是保证数据相对均衡的存储
- 由于 L1 的文件大小和数量也是受限的,所以随着数据量的增加又会触发 L1 向 L2 的 Compact。因为 L1 的文件是不重叠的,所以不用所有 L1 的文件都参与 Compact,这就延缓了磁盘 I/O 的开销。而 L2 的单个文件容量会更大,通常从 L1 开始每层的存储数据量以 10 倍的速度增长。这样,每次 Ln 到 L(n+1) 的 compact 只会涉及少数的 SSTable,间隔的时间也会越来越长。
此文章为6月Day22学习笔记,内容来源于极客时间《分布式数据库30讲》