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

75 阅读3分钟

约定 所有的数据的新增都只能追加在文件末尾,这一点就是为了保证顺序写,进而保证写的效率。 对于LSM来说,一旦刷入磁盘的数据就不在允许进行修改,后续只能进行读取。这一点也就是LSM与B+树索引最大的区别了,不需要修改就不需要去一遍遍的维护索引。LSM中所有的数据都以新增的方式刷入磁盘中,所以会有数据重复,但是索引是按照时间有序的,同一个key新的数据会直接覆盖掉旧的数据,删除数据只会新增一条删除标记。

原理 前面提到的最简单的索引方式中,所有的数据都存储在一个文件中,最简单方式的就是存储每个数据key对应的偏移量。为了防止索引过大内存中装不下,可以将文件分割成多个小文件(block)存储,索引记录block的地址,也就是记录(start_key, position)。这样每次搜索直接加载一个block中的数据进行匹配。

为了保证单个block中匹配的效率,最有效的方式就是保证单个block中的数据是有序的,这样不需要额外的结构就可以二分查找了。

所以LSM的索引结构就是存放每个block的地址,这样一种稀疏索引。

流程 当写操作到来时,会首先写入内存中(memtable)(一般会通过WAL(write-ahead logging)即预写日志,将数据的变更写入磁盘中以防止意外情况导致内存中数据丢失),memtable通过树结构来保证数据的有序性。当memtable的数据量达到一定程度之后会被写入磁盘中(sstable, sorted string table),一个全新的文件,索引记录中新增一条sstable位置的记录。由于不存在对原有文件的修改,所以写的性能要比B+树高。同时sstable是按照时间顺序创建的,所以假如同一个key同时存在于新的sstable和旧的sstable中,旧的数据被覆盖。

当进行数据读取时,会首先从内存中查找,如果没有,则按照索引逆序查找每一个sstable,直到数据被找到。

所以文件数量的多少会影响查询性能,为了降低文件数量的影响,LSM会通过后台线程定期对sstable进行合并。由于每个sstable数据都是有序的,所以利用归并的思想可以很容易的合并成一个有序的文件。

同时为了避免每个文件都被扫描一遍,LSM会为每个sstable创建一个布隆过滤器,根据布隆过滤器的特性即:如果布隆过滤器中不存在就一定不存在,可以提前规避一些不需要的sstable。

总结

LSM通过保证数据的写操作都是对磁盘的顺序操作,来保证写的效率远高于传统数据库,特别适用于写多读少的场景。