MongoDB 存储原理

407 阅读6分钟

MongoDB 存储原理

MongoDB是一个文档存储,其中文档被分组到集合中。集合在概念上可以被认为是关系表。但是,集合不会像关系表那样强加严格的架构约束。任意文档可以组合在一个集合中。但是,集合中的文档应相似,以便于有效的索引。集合可以使用命名空间进行隔离,但在内部表示不是分层的。

每个文档都以BSON格式存储。BSON 是 JSON 类型文档格式的二进制编码表示形式,其中结构接近一组嵌套的键/值对。

BSON 是 JSON 的超集,支持其他类型,如正则表达式、二进制数据和日期。每个文档都有一个唯一标识符,如果在将数据插入集合时没有明确指定,例如自动生成的对象 ID 时,MongoDB 可以生成该标识符,如图所示。

image.png

MongoDB驱动程序和客户端在访问BSON编码数据时对BSON进行序列化和反序列化。另一方面,MongoDB服务器理解BSON格式,不需要序列化的额外开销。二进制表示的读取格式与通过网络传输的格式相同。这提供了巨大的性能提升。

BSON 像协议缓冲区吗?

协议缓冲区,有时也称为protobuf,是Google编码结构化数据以实现高效传输的方式。Google将其用于其所有内部远程过程调用(RPC)和交换格式。Protobuf 是一种类似于 XML 的结构化格式,但它更轻、更快、更高效。Protobuf 是一种与语言和平台无关的规范和编码机制,可用于多种语言。

BSON 与 protobuf 相似,因为它也是一种语言和平台中立的编码机制和格式,用于数据交换和文件格式。然而,与protobuf相比,BSON更无模式。虽然较少的结构使其更加灵活,但它也剥夺了已定义架构的一些性能优势。尽管BSON与MongoDB一起存在,但没有什么能阻止你在MongoDB之外使用该格式。MongoDB驱动程序中的BSON序列化功能可以在其与MongoDB服务器交互的主要角色之外利用。

高性能是贯穿MongoDB设计的重要理念。使用内存映射文件进行存储时演示了其中一种选择。

将数据存储在内存映射文件中

内存映射文件是虚拟内存的一段,它逐字节分配给可通过文件描述符引用的文件或类似文件的资源。这意味着应用程序可以与此类文件进行交互,就好像它们是主内存的一部分一样。与通常的磁盘读写相比,这明显提高了 I/O 性能。访问和操作内存比进行系统调用要快得多。此外,在许多操作系统(如 Linux)中,映射到文件的内存区域是 RAM 中磁盘支持页面缓冲区的一部分。此透明缓冲区通常称为页面缓存。它在操作系统的内核中实现。

MongoDB使用内存映射文件进行存储的策略是一个聪明的策略,

首先,内存映射文件意味着操作系统缓存和数据库缓存之间没有分离。这意味着也没有缓存冗余。 其次,缓存由操作系统控制,因为虚拟内存映射在所有操作系统上的工作方式并不相同。这意味着控制缓存中保留的内容和丢弃的内容的缓存管理策略也因操作系统而异。 第三,MongoDB可以扩展其数据库缓存以使用所有可用内存,而无需任何额外的配置。这意味着您可以通过投入更大的RAM并分配更大的虚拟内存来增强MongoDB的性能。

内存映射也引入了一些限制。例如,MongoDB的实现将32位系统上的数据大小限制为最大2 GB。这些限制不适用于在64位计算机上运行的MongoDB。

不过,数据库大小并不是唯一的大小限制。其他限制控制每个文档的大小以及MongoDB服务器可以容纳的集合数量。文档不能大于 8 MiB,这显然意味着使用 MongoDB 存储大型 blob 是不合适的。

如果绝对需要存储大型文档,则利用 GridFS 存储大于 8 MiB 的文档。此外,可以在数据库实例中分配的命名空间数量也有限制。支持的默认命名空间数为 24,000。每个集合和每个索引都会占用一个命名空间。这意味着,默认情况下,每个集合两个索引将允许每个数据库最多 8,000 个集合。通常,这么大的数字就足够了。但是,如果需要,可以将命名空间大小提高到 24,000 以上。

增加命名空间大小也有影响和限制。每个集合命名空间最多使用几千字节。在MongoDB中,索引被实现为B树。每个 B 树页面为 8 kB。因此,添加其他命名空间(无论是用于集合还是索引)都意味着为每个附加实例添加几 kB。名为mydb的MongoDB数据库的命名空间在名为mydb.ns的文件中维护。像 mydb.ns 这样的 .ns 文件可以增长到最大大小为 2 GB。

由于大小限制可能会限制数据库的无限增长,因此了解集合和索引的更多行为模式非常重要。

在MongoDB中使用集合和索引的准则

尽管没有公式可以确定数据库中的最佳集合数,但是。建议避免将大量不同的数据放入单个集合中。将不拘一格的集合混合在一起会给索引带来复杂性。一个好的经验法则是问问自己是否经常需要查询不同的数据集。如果您的答案是肯定的,则应将数据放在一起,否则将其分成单独的集合会更有效。

有时,集合可能会无限增长,并有可能达到 2 GB 的数据库大小限制。那么使用有上限的集合可能是值得的。MongoDB中的上限集合就像一个具有预定义大小的堆栈。当上限集合达到其限制时,将删除旧数据记录。旧记录是根据最近最少使用的 (LRU) 算法标识的。在封顶集合中获取文档遵循后进先出 (LIFO) 策略。


本文正在参加「金石计划 . 瓜分6万现金大奖」