每次查找的过程如下:首先在MemTable中搜索(内存随机查找),如果没有依次在每个SSTable的索引中查找(内存随机查找)。把查找从磁盘随机动作变成了基于内存的随机动作。随着SSTable的增多,搜索的次数会增加,为了提高性能,后台会把多个SSTable合并为一个(如HBase、LevelDB等等)。并且提供布隆过滤器(BloomFilter)来过滤掉不需要的SSTable。从总体效果上看,写入的效率大大高于基于B-Tree的存储引擎,而读取性能接近于B-Tree。

LSM&SSTable在写入密集型应用中有较大优势,同时在读取方面也有不错的表现。不足之处在于上面提到的,不定期对增加的SSTable进行合并时,对于数据库会产生一定压力。

由于这些特点,LSM&SSTable大量应用于许多组件中,比如HBase、LevelDB等KeyValue数据库中,同时也在消息引擎Kafka和搜索引擎Solr使用。

列式存储

以上两种存储引擎主要适合于联机场景,如有大量的基于客户各类行为数据的批量计算的推荐系统中,以及预计客户的流动性缺口等等。在这些场景中,列式存储在性能上有非常明显的优势。随着各类大数据应用的扩展,列式存储从和Hive共生的ORC,到和Spark共生的Parquet也被应用到了各个数据分析应用中。

从传统的数据分析类应用,到人工智能应用,都需要遍历整个数据集,上面也提到磁盘在顺序读写和随机读写性能方面的巨大差距,所以所有的数据仓库都会在全表遍历中采用磁盘顺序遍历。所以遍历的文件空间越小,性能越高。列式存储按列对数据进行保存,以减少数据库每次访问的文件尺寸。

首先,分析应用一般局限于对于表中的部分字段都分析,列是存储可以让引擎只访问部分字段,减少吞吐量。其次,列式存储数据压缩能力更强。因为行级别的存储方式压缩是基于数据块,压缩比大致为50%-70%左右,而且压缩比越大,解压缩对于CPU的占用也越大。由于单列内的数据非常类似,尤其是各种码值类的数据,比如性别(男、女、其他),行数越多,压缩比越大。10亿客户的性别,也可以简单的表达为如下这样:“连续100个男性、连续50个女性、又连续80个男性、连续70个女性”,按照每行的位置依次表达下去。

再次,同样由于列内数据的取值范围有限,也可通过位图来表达,比如10表示男,01表示女,因此只用2个bit就可以表示出来,从而进一步增加压缩比。在在许多场景中能够把以前数G的数据压缩为几百K。由此可以显著降低批量计算时对于存储的吞吐压力和提升计算效率。

当然列式存储也并非完美,在更新时列式存储相对行式存储,很难直接做到就地修改的效果,往往需要把整列锁住,重新计算,重新生成整个列。所以列式存储更多的适合于数据分析时需要全表遍历的场景。