在互联网行业中,存储是一个非常重要的领域。所有的互联网应用都离不开数据的存储和检索。然而,存储系统是计算机中非常复杂的一类系统。想掌握它,不仅需要掌握数据结构、算法、操作系统等知识,还要掌握分布式系统相关知识。因此,存储领域的入门门槛较高,对于初学者或者存储爱好者而言并不友好。不幸的是,我也属于存储爱好者这个行列。此外,在日常工作和求职时,存储相关知识的运用和考察占比非常大。如果对存储系统的原理有深入的理解,在工作时能够更好地编写高效的软件,在求职时也将是明显的优势和加分项。
目前业界的存储系统主要包括关系数据库(如MySQL、Oracle等)、NoSQL数据库(如Redis、MongoDB、InfluxDB、OrientDB等)、NewSQL数据库(如TiDB、OceanBase、CockroachDB等),以及消息队列中间件(如Kafka、RocketMQ、Pulsar等)。这些存储系统绝大部分都是分布式系统,它们将多个单机节点有序地组织在一起来提供服务。如果按照模块化的思路进行拆解,这类系统可以分为单机存储组件和分布式组件。单机存储组件主要针对单个实例,关注数据如何高效地存储和检索,主要考虑数据如何组织、索引如何维护、数据如何在磁盘上布局、单机事务如何支持等问题。而分布式组件则更多关注多个实例之间的数据同步、故障发生后的故障自动迁移、数据一致性的保证、数据分片等问题。
虽然不同类型的存储系统有很多差异,但在本质上它们之间存在一些通用的技术点。市场上有几本相关的书籍介绍这些内容,比如Martin Kleppmann所著的《数据密集型应用系统设计》和Alex Petrov所著的《数据库系统内幕》等。此外,还有一些主要介绍关系数据库的书籍,比如Hector Garcia-Molina等人所著的《数据库系统实现》、Abraham Silberschatz等人所著的《数据库系统概念》和Baron Schwartz等人所著的《高性能MySQL》等。对于第一类书籍,我阅读完后发现其广度非常大,每个技术点都介绍到了,但在具体的技术专题上缺乏深度,需要搜罗其他资料进行深入学习;而第二类书籍更多的是从理论上介绍,读者阅读完以后很难直接上手去剖析任何一款数据库的源码。
2020年年底,由于工作需要,我有幸负责了单机嵌入式的KV(键值对)存储引擎的调研工作,随后接触并研究了BoltDB、LevelDB、RocksDB、PebblesDB、Bitcask等项目。在调研过程中我花费了很多的时间和精力,也走了很多弯路。当时在网上搜索了很多资料,但没有解开我内心的困惑。当时想,如果市面上有一本系统地介绍存储引擎的书就好了(比如存储引擎的分类、适用场景、设计上的共通之处及工程实现等),这样的书可以帮助我少走很多探索的弯路。后来偶然的机会接触到了《数据密集型应用系统设计》这本书,一读就被这本书的内容深深地吸引了。我反复读了第3章,每次读完书中对存储引擎简明扼要的介绍时,都有一种豁然开朗的感觉。在后来不断研究的过程中,我对单机的KV存储引擎有了深入的认识和个人理解。其间,我将其作为一个专题在团队内部和外部社区进行了分享,收到了不错的反馈,也有幸帮助到了一些技术小伙伴。
后来我想,像我当初一样,在入门存储时存在各种疑惑的初学者可能有很多。于是我决定尝试动手写一本解开上述疑惑的书,记录研究过程中的一些经验和感悟。于是,有了这本书。本书将给读者一个全新的视角,秉承大道至简的主导思想,聚焦于单机存储引擎本身,重点分析存储引擎如何处理存储和检索,编写上采用理论结合实践的方式,并给出项目源码分析。本书不仅仅是某种技能的分享,更致力于建立方法论,分享个人的一些想法和见解,希望能够抛砖引玉,为读者拓展出更深入、更全面的思路,帮助存储初学者和爱好者知其然并知其所以然。最后,希望本书能够填补存储领域的一些空白。
本书主要有三个目标。首先,分析存储引擎和各种存储系统之间的关系,使读者明确存储引擎在存储系统中的位置和角色。其次,给出存储引擎的整体框架和分类,使读者对存储引擎有全面的了解。最后,对于每种存储引擎,主要关注数据的存储和检索过程,解释每类存储引擎背后的设计思想和方案选择,使读者既知其然又知其所以然。
本书在写作上采用了理论结合实践的方式。每一类存储引擎的介绍,分为理论部分和实践部分。理论部分重点介绍设计方案和思想,不仅告诉读者每一类存储引擎能解决什么问题、适用于什么场景,还告诉读者为什么它们能解决这些问题。在介绍设计原理的基础上,配套一个开源项目进行核心源码的分析,帮助读者更深入地理解存储引擎的原理。
本书的目的不是介绍某个项目或技术,而是阐述存储引擎背后通用的设计思想和方法论。我在前人的基础上抽象和整理出来的方法论可以帮助读者更好、更快、更轻松地理解存储引擎,解决存储领域门槛较高的问题。此外,这些设计思想不局限于存储系统,读者在深刻理解后可以在计算机的其他系统中复用。因此,处于不同工作阶段的不同人群可能有不同的阅读感受,读者可以根据需要在不同阶段多次阅读本书。
在阅读本书之前,希望读者对计算机基本知识有一个大致的了解,同时具备一定的编程基础,至少熟悉一种编程语言(如C++或Go)等。如果有一些关系数据库或者其他数据库的经验会更好,否则阅读起来可能有些许困难。本书的读者对象主要包括:
❑ 数据库架构师。
❑ 开发应用架构师。
❑ 数据库开发人员。
❑ 后端开发人员。
❑ 存储、数据库爱好者。
❑ 其他计算机从业人员。
本书共9章内容,从逻辑上分为三部分。
第一部分为 存储引擎基础 ,一方面对存储引擎进行概述,另一方面介绍存储引擎中高频使用的数据结构和存储介质。这部分包括以下3章内容。
第1章 首先对互联网上的各种存储系统进行不同维度的分类,并在此基础上分析其内部数据存储的核心——存储引擎。接着对存储引擎进行分类。本章是提纲挈领的一章。
第2章 按照读/写的时间复杂度从低到高的顺序介绍存储引擎中索引高频使用的数据结构。涉及的数据结构包括数组、链表、Hash(哈希)表、位图、布隆过滤器、二叉搜索树、红黑树、跳表、B树、B+树等。
第3章 对存储引擎中的存储介质进行介绍,主要包括内存、持久化内存、磁盘等介质。本章内容涉及了大量的操作系统知识,例如虚拟内存、文件系统等。
第二部分为 基于B+树的存储引擎 ,重点讨论处理读多写少场景的B+树存储引擎的相关内容。这部分包括以下3章内容。
第4章 从宏观角度分析B+树存储引擎的原理。这一章采用了逐步推导的思路来展开介绍,告诉读者B+树存储引擎背后的方案选型和取舍。
第5章 从微观角度介绍B+树存储引擎中的细节。一方面介绍了B+树存储引擎的正常处理流程、边界条件的处理过程、异常情况的应对方案;另一方面介绍了存储引擎中事务的实现方案和多版本并发控制等内容。
第6章 以BoltDB存储引擎为例,分析其核心源码实现逻辑。本章是实践内容,通过对BoltDB核心源码的分析,使读者更好地理解B+树存储引擎的内部工作原理。
第三部分为 基于LSM派系的存储引擎 ,主要介绍处理写多读少场景的LSM派系存储引擎的相关内容。这部分包括以下3章内容。
第7章 也采用了逐步推导的方式,首先介绍LSM Tree(LSM树)存储引擎的内部原理和演变过程,其次对LSM Tree的几个核心问题(如数据合并、数据分区、放大问题、写放大优化等)进行详细的介绍。
第8章 对LSM派系的各类存储引擎(如LSM Tree、LSM Hash、LSM Array、消息队列Kafka等)进行阐述。其中,在介绍LSM Tree时重点对KV分离存储技术WiscKey进行了详细的讲解。
第9章 以LevelDB为例,对其核心源码进行剖析。通过前面两章的理论介绍和本章的源码分析,读者可以深入理解LSM Tree存储引擎的原理。
其中,第1章、第4章、第5章、第7章、第8章为本书的重点。如果你没有充足的时间阅读全书,可以选择性地阅读重点章节。
由于我的水平有限且编写时间紧张,书中难免会出现一些错误或者不准确的地方,恳请读者批评指正。读者可以通过邮箱2282186474@qq.com反馈宝贵的意见和建议,期待与大家在技术交流中互勉共进。
感谢那些为开源项目做过分享的技术大咖和发表过学术论文的学者,以及各社区和平台上的技术爱好者,尤其是《数据密集型应用系统设计》的作译者。他们的开源和分享对本书的编写起到了至关重要的作用。在编写本书的过程中,我一方面参考了大量相关论文、项目源码和资料,另一方面也参考了一些非常优秀的博客文章。这些资料对我的研究和探索也起到了非常重要的作用。
感谢我的妻子王淑明女士,为写作这本书,我牺牲了很多陪伴她的时间。也感谢我的其他家人,他们的关怀给了我坚持写作的动力。
特别感谢我职业生涯中的导师杨天琳先生,在本书写作之前的方案调研和准备过程中,他给了我很多建议。此外,在日常工作中我们进行过很多次技术讨论和交流,他给了我很多帮助。没有他在技术上的指导,我估计不会有写作本书的计划。
谨以此书献给我最亲爱的家人、朋友,以及为计算机行业做出巨大贡献的大师们。
文小飞