对比B-tree和LSM-tree
即便B-tree比LSM-tree成熟,LSM-tree也有吸引力,因为它的性能。LSM-tree写入很快,B-tree读取很快。LSM-tree读取慢,因为它不得不在压缩的各个阶段检查多个不同的数据结构和SSTable。
但是测定负载通常是不准确的,易受干扰的。你不得不使用自定的负载来测试系统,做出有效的比较。这节我们简要的讨论测量存储引擎性能时要考虑的一些事情。
LSM-tree的优势
B-tree会将每个数据至少写入两次:一次是写入写入前的日志,然后是写入树中的page(或许在page分裂时还要写入一次)。即便page只改动了一小部分,也不得不写入整个page,这很浪费资源。一些存储引擎甚至将相同page覆写两次,避免在电力故障后,page只是部分更新。
日志结构索引也会多次重写数据,因为它会重复压缩和合并SSTable。这个影响,在数据库运行时,数据库的一次写入会造成磁盘的多次写入,被称为写入扩展(write amplification)。在写入操作多的应用里,性能的主要瓶颈就是数据库写入磁盘的速率。在这种情况下,写入扩展会造成性能降低:存储引擎越多次写入磁盘,在磁盘有效带宽内,每秒能处理的写入就越少。
LSM-tree能比B-tree处理更高的写入量,一是因为它们有时候有更低的写入扩展,二是因为它会连续写入压缩SSTable而不是覆写多个page。这个区别对于机械硬盘很重要,因为它的连续写快于随机写入。
LSM-tree能被更好的压缩,所以能比B-tree生成更小的文件。B-tree存储会在磁盘上留下未使用的空间,因为分裂操作:当page被分开的时候,或者是一行数据不能适应现存的page时,一个page中的一些空间没有利用。因为LSM-tree不是以page为基础的,而是会不时重写SSTable来移除碎片,它们有着更低的存储负担,特别是使用水平压缩的时候。
LSM-trees的缺点
日志架构的存储的弱点就是压缩过程有时候会影响正在进行的读取和写入操作的性能。即便存储引擎试图增量压缩而不影响并行的操作,磁盘的资源也是有限的,很容易发生的情况是请求需要等待磁盘完成很耗资源的压缩操作。结果是吞吐量和平均响应时间很小,但是查询的响应时间大概率变得相当长,但是对B-tree而言这是可控的。
另一个压缩带来的问题是高写入吞吐量:开始时,磁盘的有限的带宽需要分配给几个前台写入程序(日志,写入mentable至磁盘),以及后台运行的压缩线程。当写入一个空的数据库时,整个磁盘的带宽用于前台写入,但是数据库增长后,需要更多的带宽用于压缩。如果写入吞吐量恨到,压缩程序没有很好的配置,可能发生的情况是压缩程序跟不上输入的写入速度;此时,没有合并的块文件就会持续增长,直到用完磁盘空间,读取也会变得很慢,因为需要检查越来越多的块文件。一般而言,基于SSTable的存储引擎不需要限制输入写入速度,即便是压缩速度更不上;所以你需要部署监控来探测这种场景。
B-tree的一个优势就是在索引中每个键值存在一个地方,但是日志结构的存储引擎在不同块文件相同的键会有多个复制的值。这个特定使得B-tree对于那些想提供强一致性的数据库很有吸引力:很多关系型数据库,传输隔离就是在键上范围加锁来实现得,在B-tree索引中,这些锁可以直接附加在树上。
B-tree非常契合数据库,在多种工作场景中提供了一直的良好性能。在新的数据存储中,日志结构索引更受欢迎。没有快捷方便的判断标准来决定那种存储引擎更适合你的应用,要根据经验判断。