当面试官抛出 LSM-tree,不知阁下该如何应对?

数据库行业在研发面试阶段经常会被问到的一项技术是什么?

答案大概率是 LSM-tree。对于数据库领域的研发同学来讲,它不仅是面试必备的问题,更是各数据库不可或缺的一项技术。不夸张地说,在近十年诞生的数据库都在使用 LSM-tree 数据结构。

今天我们就来聊上一聊,除了介绍 LSM-tree 的原理、优缺点以外,我还会列举它的典型实现,帮大家理解 LSM-tree 受各大数据库青睐的原因。

Vol.1

目前,大部分数据库都在使用基于 LSM-tree 的存储引擎,例如:RocksDB、CockroachDB、TiDB、FoundationDB、Snowflake、Doris、OceanBase、InfluxDB 等。很多朋友都知道,像 MySQL、PostgreSQL、Oracle 这些早期的数据库使用 b-tree 或其变体作为索引。那么,为什么会有那么多数据库都选择使用 LSM-tree 数据结构呢?

这就要从它的优势说起了。LSM-tree 是一个数据结构,在数据库领域主要用作主键索引,由于它 Append-only 的特性,使得在大量写入的场景有明显的优势,尤其是在 SSD 硬件普及的今天,写入优势更大。另外,由于它的分层结构、文件的不可变性,在分布式数据库中有着天然的优势。因为分布式数据库经常会做基于文件的同步、balance 等操作,不可变的文件天然就不用考虑并发、读写冲突等问题。

关于 LSM-tree 的具体理论细节,可以参考https://en.wikipedia.org/wiki/Log-structured_merge-tree。其全称是 Log-structured merge-tree,名字里没有一个词是多余的,核心的设计思路是以日志的形式存储数据,这也充分利用了磁盘的顺序读写性能高的特点,相比之下,B-tree 需要原地更新数据,所以每次写入就涉及到磁盘寻道、树分割、移动等操作,使得写入性能存在瓶颈。

但只有 append-only 还不够,因为数据库不是只有 insert 操作,还有大量的 update、delete 操作,对于 delete 则向 log 中记录一条删除记录,同时查询时只需使用最新的记录就可以满足 delete 和 update 的需求。不难发现,这样的设计非常有利于写入性能,但会占用很多额外的存储空间,即存储空间放大。所以,LSM-tree 还有额外的 compaction 机制,通过 compaction 将重复主键的数据进行清理,同时将数据按照主键进行排序以便后续查询使用,这就是名字中 merge 的来历。

至于 tree 则体现在数据是以多层的形式组织,越上层的 sstable 越小,越下层的 sstable 越大,这有利于控制 sstable 的数量,防止数据合并时的写放大。可以参考下图:

图源:interviewnoodle.com/secret-sauc...

其中数据刚写入是先进入内存的 memtable,按照一定规则 flush 进 L0 层,再按照一定 compaction 规则逐层的将数据 L0 --> L1,L1 --> L2,L2 --> L3 进行合并。LSM 的层数没有固定的值,用户需要根据写入负载、数据规模、查询性能、存储介质来权衡,一般来说数据量越大层数多,对查询性能要求高层数越浅。

看到这里,应该可以回答"为什么新兴的数据库都在使用 LSM-tree"的问题,原因是:

  • 需要存储的数据量激增,LSM-tree 在写入优势和数据存储量上有明显优势

  • SSD 等高性能存储介质普及,LSM-tree 能充分利用其性能

  • 分布式需求增加,我们不展开"分布式数据库是不是伪需求"这个敏感话题,只从现状来说分布式数据库确实有很多,而且 LSM-tree 对分布式场景更友好

  • 此外,基于 LSM-tree 的开源的 RocksDB 是个非常好的存储引擎,直接用就行了

只说优势不说缺点是不客观的,所以还是要直面 LSM-tree 的缺点:

相比于 b-tree, LSM-tree 最大的劣势就是查询性能,LSM-tree 的查询流程需要从上到下依次查询,直到查询到对应的 key 为止,最坏的情况要查询所有层,此时性能会急剧下降。对此,一些常规的优化手段是给 sstable 文件增加索引并且将其放到内存中,以加快 key 查询。

compaction 对性能的影响,compaction 期间会消耗节点的 CPU 和内存,如果资源不足对正常的写入、查询都会有影响。

通过以上的分析,不难看出 LSM-tree 是一个相对较新,对现代硬件、架构友好,但也有自身局限性的索引。接下来,后面我将通过 RocksDB 的例子,更具象化地分析 LSM-tree。

Vol.2

RocksDB 几乎可以说是现代分布式数据库的基石,大部分近十年内诞生的数据库、大数据产品都在使用或使用过RocksDB,它自身的定位是一个嵌入式的 kv 数据库,这样的定位非常适合作为一个存储引擎。

www.cockroachlabs.com/blog/cockro...这篇文章 CockroachDB 详细分析了为什么选择 RocksDB,当然由于一些其他原因,CockrochDB 后来自研了一款存储引擎 PebbleKV。

RocksDB 的历史可以追溯到 LevelDB,是 Google 开源的产品,主要应用在嵌入式设备或浏览器中,并且后期维护演进较慢。于是,Facebook 的 Dhruba Borthakur 于 2012 年 4 月 Fork 了 LevelDB,在其基础之上改进了服务器工作负载的性能,以充分利用多核处理器和快速存储设备的性能,特别适用于 I/O 密集型工作负载。

RocksDB 不只实现了 LSM-tree 数据结构,还在此之上增加了一系列存储引擎的功能,例如 ACID 支持、事务、WAL、丰富的查询接口、快照、TTL、列簇等功能,

图源:github.com/facebook/ro...

在 Facebook 内部,基于 RocksDB 实现了一个 MyRocks 项目,用来替换 MySQL 的 InnoDB 引擎,性能测试的结果显示在写入场景中远超 MySQL,查询性能也相差不大。其实对于一款数据库产品来讲,写入的性能往往更关键,毕竟想要更好的查询性能可以用 OLAP 数据库,而 OLAP 数据库往往对存储引擎的需求没那么大。

Vol.3

之前的分析都在讲 LSM-tree 适合高吞吐、SSD 的场景,但现在数据库技术的发展趋势是存算分离、云原生,这种场景无疑会带来新的挑战。例如,本地文件读写变成了远程调用,多节点之间的并发读写冲突等问题。

对于这些问题,大厂是如何解决的?以 Facebook 为例,近期他们发表了一篇文章总结了他们在存算分离场景的最佳实践。读下来,感觉 Facebook 的基础架构在其他公司不一定适用,经验不一定能直接移植,但他们解决问题的思路是值得借鉴的。

首先,Facebook使用了内部的一套分布式文件系统 Tectonic File System,与 HDFS 类似但是自研的,所以性能、适用场景肯定和 HDFS 有区别。其次,这次改造的目标也很明确,就是节约成本,存算一体架构最大的问题是资源使用率不足,往往存储已经满了但 CPU 还没跑满,而且存算一体需要为每个应用预留存储空间资源浪费,而存算分离可以让资源尽量复用。

存算分离对 RocksDB 来说,有几个挑战,分别是:

  • 性能相比使用本地磁盘差

  • 增加很多额外开销,本地磁盘获取文件列表、统计信息等几乎没有延迟,而分布式系统不同,都有额外的开销

  • 使用本地磁盘时,多个节点之间的数据天然隔离的,而存算分离场景下存储是在同一个目录,需要解决多个 writer 并发修改的问题

  • 故障处理更复杂,需要进行大量代码改造

针对上述问题,Facebook 进行了大量优化,包括优化尾部 IO 延迟、metadata 缓存、计算节点缓存、并行 IO、优化 compaction 策略等来提升性能;通过 IO fencing 技术解决存储并发冲突;不使用纠删码而使用多副本降低额外开销;增加大量 tracing、监控等手段发现瓶颈点、异常逐步解决。

经过实验存储引擎的写吞吐大概降低 25%,读延迟大概有 3~5 倍。实话实说,这个结果已经很不错了,毕竟网络再怎么优化也是比本地磁盘多了一层开销。

Facebook 还做过这样的实验:把内部的 ZipplyDB 中的 RocksDB 替换成存算分离版本,空间使用率从原来的 35% 提升到了 75%,故障恢复时间从 51 min 优化到了 49 s,而端到端的写延迟几乎没有影响,P99 的读延迟增加了 50%。这个结果还挺不错的,相对于性能的一点损失,资源使用率提升太明显了,同时故障恢复时间降低了太多,能够大大提升运维的便捷度,意味着运维遇到问题时敢于重启了。

总的来说,Facebook 可以把 RocksDB 改成存算分离版本,并从中拿到很好的结果,说明这条路是可行的。当然,这只是个例,是否具有普适性还有待验证。毕竟 Facebook 的基建优势和人才储备,其他公司大概率不具备类似的条件。

Vol.4

本文从 LSM-tree 的原理一路讲到了它最火热的开源实现 RocksDB,又延伸出一些 RocksDB 在存算分离方面的探索,存储技术一路进化的推动力是底层存储介质的变化,用户对性能、成本越来越高的期待,以及技术人不断的探索。未来,可能会有更适合时代的存储技术出现,并慢慢取代 LSM-tree(就像 b-tree 慢慢地被取代一样),但当下这个时间点,学好 LSM-tree、RocksDB 技术,在数据库行业混口饭吃还是绰绰有余的。

引用

相关推荐
徐小黑ACG1 小时前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
·薯条大王3 小时前
MySQL联合查询
数据库·mysql
战族狼魂4 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
morris1315 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch5 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
bobz9656 小时前
k8s 怎么提供虚拟机更好
后端
这个懒人6 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
Yan-英杰6 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql
bobz9656 小时前
nova compute 如何创建 ovs 端口
后端