读多写少
LSM 树是一个基于磁盘的数据结构,它设计的主要目的是为长期需要高频率写入操作的文件提供低成本的索引机制8。无论是 B 树还是 B+ 树,向这些数据结构组成的索引文件中写入记录都需要执行的磁盘随机写,LSM 树的优化逻辑就是牺牲部分的读性能,将随机写转换成顺序写以优化数据的写入。
我们在这篇文章不会详细介绍为什么 LSM 树有着较好的写入性能,我们只是来分析为什么 WiredTiger 使用 B 树作为默认的数据结构。WiredTiger 对 LSM 树和 B 树的性能进行了读写吞吐量的基准测试9,通过基准测试得到了如下图所示的结果,从图中的结果我们能发现:
在不限制写入的情况下;
LSM 树的写入性能是 B 树的 1.5 ~ 2 倍;
LSM 树的读取性能是 B 树的 1/6 ~ 1/3;
在限制写入的情况下;
LSM 树的写入性能与 B 树的性能基本持平;
LSM 树的读取性能是 B 树的 1/4 ~ 1/2;
在限制写入的情况下,每秒会写入 30,000 条数据,从这里的分析结果来看,无论那种情况下 B 树的读取性能是远好于 LSM 树的。对于大多数的系统来说,系统的查询会是写的很多倍,所以 LSM 树在写入方面的优异表现也没有办法让它成为 MongoDB 默认的数据格式。
总结
应用场景永远都是系统设计时首先需要考虑的问题,作为 NoSQL 的 MongoDB,其目标场景就与更早的数据库就有着比较大的差异,我们来简单总结一下 MongoDB 最终选择使用 B 树的两个原因:
MySQL 使用 B+ 树是因为数据的遍历在关系型数据库中非常常见,它经常需要处理各个表之间的关系并通过范围查询一些数据;但是 MongoDB 作为面向文档的数据库,与数据之间的关系相比,它更看重以文档为中心的组织方式,所以选择了查询单个文档性能较好的 B 树,这个选择对遍历数据的查询也可以保证可以接受的时延;
LSM 树是一种专门用来优化写入的数据结构,它将随机写变成了顺序写显著地提高了写入性能,但是却牺牲了读的效率,这与大多数场景需要的特点是不匹配的,所以 MongoDB 最终还是选择读取性能更好的 B 树作为默认的数据结构;
到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:
BigTable、LevelDB 和 HBase 的应用场景都是什么?它们的读写比例有多少?为什么使用 LSM 树作为底层的数据结构?
在设计表结构时,MongoDB 与传统的关系型数据库有哪些区别?
如果对文章中的内容有疑问或者想要了解更多软件工程上一些设计决策背后的原因,可以在博客下面留言,作者会及时回复本文相关的疑问并选择其中合适的主题作为后续的内容。
相关文章
MongoDB 官方网站 The database for modern applications https://www.mongodb.com/ ↩
分布式键值存储 Dynamo 的实现原理 https://draveness.me/dynamo ↩
NoSQL 维基百科 https://en.wikipedia.org/wiki/NoSQL ↩
NoSQL (Not Only SQL database) https://searchdatamanagement.techtarget.com/definition/NoSQL-Not-Only-SQL ↩
『浅入浅出』MongoDB 和 WiredTiger https://draveness.me/mongodb-wiredtiger ↩
MongoDB 中的集合(Collection)与 MySQL 中的表(Table)是差不多的概念 ↩
为什么 MySQL 使用 B+ 树 · Why’s THE Design? https://draveness.me/whys-the-design-mysql-b-plus-tree ↩
The Log-Structured Merge-Tree (LSM-Tree), Patrick O’Neil, Edward Cheng, Dieter Gawlick, Elizabeth O’Neil https://www.cs.umb.edu/~poneil/lsmtree.pdf ↩
Btree vs LSM https://github.com/wiredtiger/wiredtiger/wiki/Btree-vs-LSM ↩
本文转载自 Draveness 技术博客。
原文链接:https://draveness.me/whys-the-design-mongodb-b-tree
评论