SSTabble的定义
SStable是排序字符串表,顺序存储key的key-value日志格式,要求每个key在合并的段文件中只出现一次(在压缩的过程中确保)
SSTable相较于纯哈希索引日志段的优点
- 合并段更高效,支持文件大于可用内存
合并方法类似于归并排序,并发读取多个输入文件,比较每个文件的第一个key,将最小的key拷贝输出到文件,重复这个过程,最后生成一个按键排序的合并段。如果相同的键存在多个value,用最新的value进行更新。 - 在文件中查找特定key时,不需要在内存中保存所有key 的索引,可以根据SSTable的有序性以及key的偏移量进行查找。
比如需要查找key:house,在不知道key在段文件中的偏移量的情况下,如果知道home和how的偏移量,由于键是有序的,则house一定在他们两个之中。所以任然需要知道一个内存索引来记录某些key的偏移,但是索引可以是稀疏的,不必保存所有的key。
ps:如果所有key和value都有固定的大小,则可以在分段文件上使用二分查找,并完全不需要在内存中保存索引。但是由于工程中都是可变长度的,没有索引的话,很难确定一条log的开始和结束的位置。 - 将多条log保存到一个块中,并在写磁盘之前将其压缩,然后稀疏的内存索引的每个条目指向每个压缩块的开头,用以节省磁盘空间和I/O带宽的占用。
SSTable的构建
并发写入可能让log以任意的顺序出现,如何让数据按key排序呢。
- 在磁盘上排序(B-Tree)
- 在内存上排序(红黑树/AVL树)
使用内存排序的存储引擎基本工作流程
- log写入时,将其添加到内存中的平衡树(内存表)数据结构中。
- 当内存大于某个阈值(通常为若干MB,如redis自动aof的size是64mb)时,将其作为SSTable文件写入磁盘。由于树已经维护了按key排序的key-value对,写磁盘可以相对高效。新的SSTable已经成为数据库的最新部分。当SSTable写磁盘的时候,写入可以继续添加到一个新的内存表实例。
- 每次处理读请求,首先常识在内存表中查找key,然后是最新的磁盘段文件,然后是次新的磁盘段文件,以此类推,直到找到目标或者为空。
- 后台进程周期性地执行合并与压缩的过程,来合并多个段文件,并丢弃哪些被覆盖或者被删除的部分。
- 如果数据库崩溃,在内存表中但是尚未写入磁盘的log将会丢失,为了避免这种情况,可以在磁盘上保存单独的日志,每个写入都会立刻追加到日志。日志文件不需要按键排序,它唯一的目的是在崩溃中恢复内存表,当内存表写入SSTable时,相应的日志就可以被丢弃了。