对比Postgres和MongoDB


为何对比 Postgres 和 MongoDB,因为前面有《PostgreSQL与MySQL两大开源数据库比较》。
根据 2023 年 Stack Overflow 调研,Postgres 已经成为最受欢迎和渴望的数据库了。本节转自Bytebase的博客空间,感谢原作者。

MongoDB 曾连续 4 年 (2017 - 2020) 蝉联此头衔。根据 DB-Engines 排名,Postgres 和 MongoDB 都是排名前 5 的数据库。它们两者都在爬楼梯,并且在夺取三大巨头:Oracle, MySQL 和 Microsoft SQL Server 的市场份额。

MongoDB 被广泛认为是一种与包括 Postgres 在内的 SQL 数据库相对立的 NoSQL 数据库。但近年来它们正在趋同:
1.MongoDB 变得更像传统关系型数据库,增加了多文档 ACID 事务,二级索引和高级查询功能。
2.Postgres 不断改进其 JSON 能力,如索引、查询优化和更多操作符,这不禁让人们好奇 MongoDB 是否已经过气。
2018 年,The Guardian 写了一篇关于将 MongoDB 迁移到 Postgres 的长文。自此虽然发生了很多变化,但有一件事没变:迁移数据库是极其痛苦的。
因为需要与各种数据库及其衍生产品集成,Bytebase 和各种数据库密切合作,而最大的数据库托管服务 Google Cloud SQL 也是 Bytebase 创始人的杰作之一。
根据实操经验对此两者在以下几个维度进行了比较:
许可证 License
数据模型 Data Model
JSON 支持 JSON Support
性能 Performance
可靠性 Reliability
伸缩性 Scalability
易用性 Usability
可运维性 Operability
生态系统 Ecosystem
除非另有说明,下文基于最新的主要版本 Postgres 15 和 MongoDB 6。在文章中使用 Postgres 而不是 PostgreSQL,虽然 PostgreSQL 才是官方名称,但被认为是 Postgres 史上最错误的决定。
许可证 License
Postgres 发布在 PostgreSQL 许可下,是一种类似于 BSD 或 MIT 的自由开源许可。MongoDB 社区版采用由 MongoDB 公司自行创建的 Server Side Public License (SSPL) 发布,以防止他人提供竞争性的 MongoDB 服务,MongoDB 公司还根据要求提供商业许可证。
大多数公司使用数据库来支持其内部基础设施,Postgres 和 MongoDB 都允许此类使用。
数据模型 Data Model
Postgres 是关系型数据库,它将数据存储在预先定义好的列中,并通过使用外键来建立表之间的关系。MongoDB 是面向文档的数据库,这意味着数据以文档形式存储在集合中。每个文档都是一个类似 JSON 的结构,可以包含嵌套字段和数组。MongoDB 专为处理非结构化和半结构化数据而设计。

Postgres 也支持 JSON 列,因此可以像使用 MongoDB 一样使用 Postgres,将表定义为:
CREATE TABLE my_collection (
id SERIAL PRIMARY KEY,
data JSONB
);
JSON 支持 JSON Support
MongoDB 和 Postgres 都非常擅长处理 JSON。MongoDB 使用自己发明的 BSON 格式存储 JSON,而 Postgres 使用 JSONB 格式。如果有兴趣,可以看下这个关于选择在 Postgres 中使用 BSON 还是 JSONB 之间的讨论。
MongoDB 有两个优点:
1.内置 schema 验证器。
2.与 Node.js/前端生态系统的集成。MongoDB 是全栈开发人员常用的选择,他们通常会使用 Node 进行开发。
性能 Performance
性能主要由访问模式决定。如果一个操作涉及不同的实体,MongoDB 通常更快,因为数据是 denormalized 的,并且不需要在表之间进行复杂的连接操作。另一方面,Postgres 能处理复杂查询,这得益于 SQL 和其先进的查询优化器。
可靠性 Reliability
MongoDB 在早期因为不支持 ACID 事务而被认为是不太靠谱的。不过自从他们收购了 WiredTiger 并使用其 WiredTiger 存储引擎后,就不一样了。从事务角度来看,如今的 MongoDB 和 Postgres 一样稳定可靠。
MongoDB 通过其副本集提供内置的自动 failover 功能。而 Postgres 则需要像类似 pg_auto_failover 的第三方解决方案。
伸缩性 Scalability
MongoDB 可以进行横向扩展 (scale out),而 Postgres 通常则是纵向扩展 (scale up)。MongoDB 是一个支持自动分片的分布式数据库。对于 Postgres 来说,通常会先将单节点的 postgres 进行纵向扩展,并尽可能地推迟使用分片解决方案。当然对 Postgres 进行分片是可以的:
1.分片和 ID 在 Instagram 的使用
2.驯服大象:Notion 在 Postgres 上进行分片的经验教训
易用性 Usability
MongoDB 不会事先强制 schema,并且容易上手。在 2010 年,10gen(开发 MongoDB 的公司的原名)发布了官方 MongoDB Node.js 驱动程序的第一个版本,开发人员能轻松地从 Node.js 应用程序与 MongoDB 数据库进行交互。该驱动程序提供了一个简单直观的 API,支持广泛的 MongoDB 功能,包括查询、索引和聚合等。正因为好用,如今MongoDB仍是全栈开发人员首选。
作为关系型数据库,Postgres 强制对 schema 进行了约束。而即使在关系型数据库中,Postgres 也比其他产品如 MySQL 更加严格。
Stack Overflow 的调查显示,尽管 Postgres 是受访者中最受欢迎的数据库,但 MongoDB 在新手中更受欢迎。
而在处理复杂查询方面,MQL (MongoDB Query Language) 则不如 SQL 强大。
可运维性 Operability
运行多节点的 MongoDB 比运行多节点的 Postgres 更容易,因为分片和 failover 可以由 MongoDB 来处理。不过,如果在单个节点上分别运行这两个数据库,那么 MongoDB 的分布式特性可能会成为负担。
各种第三方供应商提供了 Postgres 托管服务。MongoDB 的 License 阻止了第三方提供 MongoDB 托管服务,不过他们自己的 MongoDB Atlas 比对应的 Postgres 托管服务更加完善。毕竟第三方很难击败第一方云服务。
生态系统 Ecosystem
Postgres 有可扩展的架构,并且仍由社区维护。近年来,Postgres 生态系统蓬勃发展,它拥有众多插件,使其能够处理比其他数据库更多样化的任务。而且由于其自由许可证和坚实的架构,在每个应用程序平台提供托管数据库服务时,它们都选择了 Postgres,从早期的 Heroku 到新兴的 Supabase, render 和 Fly.io。
MongoDB 作为市值最高的商业开源企业采取了更商业化的做法。一旦在生态系统中出现了优秀解决方案,MongoDB 公司都会考虑收购以确保其成为整体 MongoDB 产品线不可或缺的一部分。其中一些著名的收购包括:
1.WiredTiger 存储引擎
2.mLab 托管服务
3.Realm 移动端数据同步方案
4.Compass MongoDB GUI 客户端
尽管这两者采取了截然不同的方式来培育生态系统,但都取得了巨大成功。
Postgres or MongoDB

在某些领域中,明显一个数据库比另一个更合适:
1.如果应用程序具有复杂的业务逻辑并且需要复杂查询,请选 Postgres。
2.如果应用程序具有简单的数据模型并需要处理海量数据,请选 MongoDB。
然而,大多数应用程序用例介于两者之间,而且两个数据库都非常强大:
1.作为文档型数据库,MongoDB 提供了一流的 JSON 支持。而 Postgres 在开源关系型数据库中也有着最好的 JSON 支持。
2.对于全栈开发人员来说,MongoDB 曾经是首选,因为它与 Node.js 完美集成。而随着主要第三方应用平台都提供托管 Postgres 服务,其则变得愈发有吸引力。
3.对于后端开发人员来说,在添加事务支持后,MongoDB 变得更加诱人了。谁不想避免繁琐的 schema 更改并享受更快速的迭代呢?
4.MongoDB Atlas 构建了最精细化的托管数据库服务之一;而各种大小第三方供应商则都提供了出色的 Postgres 托管解决方案。
总体而言,Postgres 是一个更通用的数据库,它采用关系模型、提供全面 SQL 功能、具备可扩展架构,并由一个热情洋溢的社区推动。MongoDB 是一个全面的数据库解决方案,它普及了文档模型、内置了伸缩性和高可用性,提供了完整的开发者体验,并由一个敏锐的营利性商业实体推动着。如果在 Postgres 和 MySQL 之间做选择很困难,那么在 Postgres 和 MongoDB 之间选择也不容易。而且随着两个数据库都朝着更强的方向发展,选择只会变得越来越困难。
最后,在一个组织内部 Postgres 和 MongoDB 共存也是很常见的情况。
Infisical从MongoDB迁移到PostgreSQL
本节总结自Bytebase的博客空间,虽然 MongoDB 在早期为 Infisical 提供了良好的服务,但当我们的产品场景不单单是托管服务时,它开始显示出不足之处。随着时间的推移,我们发现许多组织,特别是那些在合规和安全交叉点运营的组织,更喜欢自托管 Infisical 而非使用 Infisical Cloud;其他的有一些本地需求需要满足。
随着对自托管 Infisical 的需求增长,我们发现自己正在开发许多功能以减少学习如何自我托管 Infisical 所需的曲线,并且作为其中一部分,最终放弃了 MongoDB 转而支持 PostgreSQL。实际上,在能力和可用性方面和客户经常遇到 MongoDB 带来的限制问题,比如缺乏对事务、清理、云托管产品中版本一致性的支持,更不同提与 schema-less 数据库设计结构相关联的问题了。
以下是对其中一些挑战的详细解释:
1.配置数据库事务困难:使用 MongoDB,设置事务并不简单,因为它需要在集群模式下运行 MongoDB,并有各种配置开销;这使得客户要运行一个简单的 Infisical POC 变得极其困难,因为它需要生产环境下的 MongoDB 设置。对于处理高度敏感数据且数据完整性必须保证的产品来说,这是无法接受的。
2.缺少关系型特性:使用 MongoDB 后,我们失去了许多来自关系型世界的好功能,比如 CASCADE,当目标资源被删除时,可以删除其他表中所有被引用资源;这尤其令人痛苦,因为我们的数据非常依赖关系型。结果是,在我们旧代码库中采用了大量删除函数却从未能完全完成任务,并在 MongoDB 数据库中留下悬空资源。
3.云提供商支持不足:在 MongoDB 将许可更改为 SSPL 后,许多云提供商选择提供较老版本的 MongoDB。结果是,我们发现很难确保 Infisical 的功能可用性,除非是运行最新稳定版 MongoDB 的客户。
4.缺乏操作 MongoDB 的经验:由于更多人熟悉部署基于 SQL 的数据库,他们经常在扩展和正确配置 MongoDB 上遇到困难;这导致我们需要为客户提供的支持量不成比例地增加,特别是因为他们对 MongoDB 不熟悉。
出于以上以及其他更多原因,意识到使 Infisical 能够被世界各地的团队和组织更广泛接受所需的最重要功能,其实是需要全面迁移至更加通用的数据库。在寻找新的数据库时,我们首先列出了对我们最重要的几个方面:管理便利性(即包括配置、部署和扩展),内置事务支持,以及关系型功能。在讨论过程中,我们还考虑了是否应该构建自己的集成存储或寻求外部存储解决方案。
以下是每个选项的意义:
1.集成存储:我们可以将像 SQLite 这样的数据库系统直接打包到 Infisical 中,并采用水平复制策略来通过避免额外的网络跳转来减少延迟。在这个模型中,扩展系统意味着部署多个 Infisical 实例,并让它们通过某种共识算法(如 Raft)进行相互通信。虽然这看起来是一个极好的解决方案,因为客户不需要连接任何依赖项就能运行 Infisical,但执行此愿景所需的工具生态系统感觉还不够成熟,而且所需的工程努力也太强人所难了。
2.外部存储:我们可以简单地用 PostgreSQL 或 MySQL 等其他数据库替换 MongoDB,并使用其内置的扩展功能。尽管这个解决方案并没有完全消除使用 Infisical 时需要外部依赖项带来的摩擦,但我们认为它已经通过不再是 MongoDB,而带来了显著的优点。当涉及到支持一个或多个数据库时,我们认为支持多个会错过每种解决方案各自独特的优点;同时也会增加我们的工程开销。
经过慎重考虑,我们选择了 PostgreSQL。除了拥有活跃的社区、详尽的文档以及大量可用的解决方案和扩展外,我们最欣赏的是它开源的本质以及绝大多数云服务提供商都提供 PG的托管服务。这意味着 Infisical 的用户可以更容易地在任何云服务提供商上自行部署我们的平台,并将其与相应的托管 PostgreSQL 服务配对使用。此外,鉴于该数据库已被广泛采用,我们有信心用户在使用 Infisical 时操作起来会更加顺畅。
鉴于 Infisical 在客户基础设施中的关键作用,我们立即排除了有任何绝对停机时间的可能性。我们不得不做出妥协的部分是,在短暂的迁移窗口期间禁止写入操作(即客户无法创建或更新应用配置),以换取保证数据完整性。这种权衡似乎可以接受,因为客户主要从 Infisical 获取秘密信息。很少他们会每秒钟更新应用配置。
接下来,关于实际迁移操作,需要从 MongoDB 导出数据、仔细转换它,并将其重新插入到 PostgreSQL 中。当我们审计迁移序列时,面临着诸如确保各种树形结构从 NoSQL 正确地转化为它们关系型数据库等价物;这对于具有递归考虑因素的文件夹等数据结构特别敏感。我们还发现需要一种持久化方式来存储和映射 MongoDB 中与 PostgreSQL 中相同标识符;如果只依赖内存处理,考虑到我们处理的数据量之大,这是行不通的。最后我们选择使用 LevelDB 键值存储来协助标识符存储和查找操作。有了它,我们可以逐表地将数据移入 PostgreSQL 中。
最后准备进行迁移。在此之前,那些没有直接参与代码库重写的人员已经花了一个季度来改进 Infisical 的其他方面,包括进行前端更改、打维护补丁、扩展客户端功能,并编写更好的文档。现在我们所有人都重新聚集起来为迁移本身做准备,即用新的替换应用程序代码库,并将数据从 MongoDB 转移到 PostgreSQL。
作为准备工作的一部分,制定了一份详细的迁移清单和预期时间表。计划大致如下:
1.在迁移的几周前,我们会通过电子邮件和应用内横幅提前通知用户即将进行的数据库升级。我们将对平台上的每个功能流程进行彻底测试,并为迁移进行试运行。
2.迁移本身将在一个六小时的窗口期内发生,在此期间只允许对平台进行读取操作。在这个窗口期,我们会运行迁移脚本,把数据从 MongoDB 转移到 PostgreSQL,检查是否有数据丢失,并且如果成功就把 DNS 切换到新实例。当然,如果事情出现问题,我们已经备好了应急方案。
3.最后,在迁移之后,我们会解决任何残留问题,并开始推出 Infisical 和 PostgreSQL 一起工作的新文档。
幸运的是,迁移执行过程非常顺利,没有数据丢失,只有少数非关键功能出现故障;在接下来的 36 小时内解决了这些问题,并将对客户的影响降到最低。
在2024年年初完成迁移之后,我们观察到了许多好处:
1.平台的性能大幅提升,主要归因于对连接查询的优化。使用 MongoDB 时,平台经常需要进行效率低下的聚合查询和多次网络跳转以实现所需功能。例如,由于我们核心数据的关系特性,我们经常需要执行许多 $lookup 操作来模拟 SQL 中的连接;这些操作效率低下,并且通常需要我们相应地扩展数据库和应用实例。迁移到 PostgreSQL 后,我们避免了这些效率低下的操作,也使得数据库账单上的成本减少了 50%。
2.现在的平台采用更好的数据验证方式,在数据库层面而不是应用层面进行根源处理。由于 MongoDB 设计上没有 schema 约束,它依赖 Mongoose 框架定义数据类型、必填字段和验证规则。有了 PostgreSQL, 我们再也不会面临如果数据库被绕过 Mongoose 范围访问或修改时可能出现的数据不一致问题。
3.最后并且最重要的是,我们认为 Infisical 现在更容易自我托管,客户可以无需额外配置开销 (如处理 MongoDB 中启用事务功能所需的 replica sets) 就能进行 POC 测试。总体来说,考虑到手头目标、任务范围及其执行结果,我们认为这项举措非常成功。一旦我们有更多数据,我们计划在未来发布更具体的结果。
总的来说,考虑到手头的目标、任务的范围以及最终执行情况,我们认为这次的迁移非常成功。一旦有了更多的数据,我们打算在未来发布更具体的结果。
根据 2023 年 Stack Overflow 调研,Postgres 已经成为最受欢迎和渴望的数据库了。本节转自Bytebase的博客空间,感谢原作者。

MongoDB 曾连续 4 年 (2017 - 2020) 蝉联此头衔。根据 DB-Engines 排名,Postgres 和 MongoDB 都是排名前 5 的数据库。它们两者都在爬楼梯,并且在夺取三大巨头:Oracle, MySQL 和 Microsoft SQL Server 的市场份额。

MongoDB 被广泛认为是一种与包括 Postgres 在内的 SQL 数据库相对立的 NoSQL 数据库。但近年来它们正在趋同:
1.MongoDB 变得更像传统关系型数据库,增加了多文档 ACID 事务,二级索引和高级查询功能。
2.Postgres 不断改进其 JSON 能力,如索引、查询优化和更多操作符,这不禁让人们好奇 MongoDB 是否已经过气。
2018 年,The Guardian 写了一篇关于将 MongoDB 迁移到 Postgres 的长文。自此虽然发生了很多变化,但有一件事没变:迁移数据库是极其痛苦的。
因为需要与各种数据库及其衍生产品集成,Bytebase 和各种数据库密切合作,而最大的数据库托管服务 Google Cloud SQL 也是 Bytebase 创始人的杰作之一。
根据实操经验对此两者在以下几个维度进行了比较:
许可证 License
数据模型 Data Model
JSON 支持 JSON Support
性能 Performance
可靠性 Reliability
伸缩性 Scalability
易用性 Usability
可运维性 Operability
生态系统 Ecosystem
除非另有说明,下文基于最新的主要版本 Postgres 15 和 MongoDB 6。在文章中使用 Postgres 而不是 PostgreSQL,虽然 PostgreSQL 才是官方名称,但被认为是 Postgres 史上最错误的决定。
许可证 License
Postgres 发布在 PostgreSQL 许可下,是一种类似于 BSD 或 MIT 的自由开源许可。MongoDB 社区版采用由 MongoDB 公司自行创建的 Server Side Public License (SSPL) 发布,以防止他人提供竞争性的 MongoDB 服务,MongoDB 公司还根据要求提供商业许可证。
大多数公司使用数据库来支持其内部基础设施,Postgres 和 MongoDB 都允许此类使用。
数据模型 Data Model
Postgres 是关系型数据库,它将数据存储在预先定义好的列中,并通过使用外键来建立表之间的关系。MongoDB 是面向文档的数据库,这意味着数据以文档形式存储在集合中。每个文档都是一个类似 JSON 的结构,可以包含嵌套字段和数组。MongoDB 专为处理非结构化和半结构化数据而设计。

Postgres 也支持 JSON 列,因此可以像使用 MongoDB 一样使用 Postgres,将表定义为:
CREATE TABLE my_collection (
id SERIAL PRIMARY KEY,
data JSONB
);
JSON 支持 JSON Support
MongoDB 和 Postgres 都非常擅长处理 JSON。MongoDB 使用自己发明的 BSON 格式存储 JSON,而 Postgres 使用 JSONB 格式。如果有兴趣,可以看下这个关于选择在 Postgres 中使用 BSON 还是 JSONB 之间的讨论。
MongoDB 有两个优点:
1.内置 schema 验证器。
2.与 Node.js/前端生态系统的集成。MongoDB 是全栈开发人员常用的选择,他们通常会使用 Node 进行开发。
性能 Performance
性能主要由访问模式决定。如果一个操作涉及不同的实体,MongoDB 通常更快,因为数据是 denormalized 的,并且不需要在表之间进行复杂的连接操作。另一方面,Postgres 能处理复杂查询,这得益于 SQL 和其先进的查询优化器。
可靠性 Reliability
MongoDB 在早期因为不支持 ACID 事务而被认为是不太靠谱的。不过自从他们收购了 WiredTiger 并使用其 WiredTiger 存储引擎后,就不一样了。从事务角度来看,如今的 MongoDB 和 Postgres 一样稳定可靠。
MongoDB 通过其副本集提供内置的自动 failover 功能。而 Postgres 则需要像类似 pg_auto_failover 的第三方解决方案。
伸缩性 Scalability
MongoDB 可以进行横向扩展 (scale out),而 Postgres 通常则是纵向扩展 (scale up)。MongoDB 是一个支持自动分片的分布式数据库。对于 Postgres 来说,通常会先将单节点的 postgres 进行纵向扩展,并尽可能地推迟使用分片解决方案。当然对 Postgres 进行分片是可以的:
1.分片和 ID 在 Instagram 的使用
2.驯服大象:Notion 在 Postgres 上进行分片的经验教训
易用性 Usability
MongoDB 不会事先强制 schema,并且容易上手。在 2010 年,10gen(开发 MongoDB 的公司的原名)发布了官方 MongoDB Node.js 驱动程序的第一个版本,开发人员能轻松地从 Node.js 应用程序与 MongoDB 数据库进行交互。该驱动程序提供了一个简单直观的 API,支持广泛的 MongoDB 功能,包括查询、索引和聚合等。正因为好用,如今MongoDB仍是全栈开发人员首选。
作为关系型数据库,Postgres 强制对 schema 进行了约束。而即使在关系型数据库中,Postgres 也比其他产品如 MySQL 更加严格。
Stack Overflow 的调查显示,尽管 Postgres 是受访者中最受欢迎的数据库,但 MongoDB 在新手中更受欢迎。
而在处理复杂查询方面,MQL (MongoDB Query Language) 则不如 SQL 强大。
可运维性 Operability
运行多节点的 MongoDB 比运行多节点的 Postgres 更容易,因为分片和 failover 可以由 MongoDB 来处理。不过,如果在单个节点上分别运行这两个数据库,那么 MongoDB 的分布式特性可能会成为负担。
各种第三方供应商提供了 Postgres 托管服务。MongoDB 的 License 阻止了第三方提供 MongoDB 托管服务,不过他们自己的 MongoDB Atlas 比对应的 Postgres 托管服务更加完善。毕竟第三方很难击败第一方云服务。
生态系统 Ecosystem
Postgres 有可扩展的架构,并且仍由社区维护。近年来,Postgres 生态系统蓬勃发展,它拥有众多插件,使其能够处理比其他数据库更多样化的任务。而且由于其自由许可证和坚实的架构,在每个应用程序平台提供托管数据库服务时,它们都选择了 Postgres,从早期的 Heroku 到新兴的 Supabase, render 和 Fly.io。
MongoDB 作为市值最高的商业开源企业采取了更商业化的做法。一旦在生态系统中出现了优秀解决方案,MongoDB 公司都会考虑收购以确保其成为整体 MongoDB 产品线不可或缺的一部分。其中一些著名的收购包括:
1.WiredTiger 存储引擎
2.mLab 托管服务
3.Realm 移动端数据同步方案
4.Compass MongoDB GUI 客户端
尽管这两者采取了截然不同的方式来培育生态系统,但都取得了巨大成功。
Postgres or MongoDB

在某些领域中,明显一个数据库比另一个更合适:
1.如果应用程序具有复杂的业务逻辑并且需要复杂查询,请选 Postgres。
2.如果应用程序具有简单的数据模型并需要处理海量数据,请选 MongoDB。
然而,大多数应用程序用例介于两者之间,而且两个数据库都非常强大:
1.作为文档型数据库,MongoDB 提供了一流的 JSON 支持。而 Postgres 在开源关系型数据库中也有着最好的 JSON 支持。
2.对于全栈开发人员来说,MongoDB 曾经是首选,因为它与 Node.js 完美集成。而随着主要第三方应用平台都提供托管 Postgres 服务,其则变得愈发有吸引力。
3.对于后端开发人员来说,在添加事务支持后,MongoDB 变得更加诱人了。谁不想避免繁琐的 schema 更改并享受更快速的迭代呢?
4.MongoDB Atlas 构建了最精细化的托管数据库服务之一;而各种大小第三方供应商则都提供了出色的 Postgres 托管解决方案。
总体而言,Postgres 是一个更通用的数据库,它采用关系模型、提供全面 SQL 功能、具备可扩展架构,并由一个热情洋溢的社区推动。MongoDB 是一个全面的数据库解决方案,它普及了文档模型、内置了伸缩性和高可用性,提供了完整的开发者体验,并由一个敏锐的营利性商业实体推动着。如果在 Postgres 和 MySQL 之间做选择很困难,那么在 Postgres 和 MongoDB 之间选择也不容易。而且随着两个数据库都朝着更强的方向发展,选择只会变得越来越困难。
最后,在一个组织内部 Postgres 和 MongoDB 共存也是很常见的情况。
Infisical从MongoDB迁移到PostgreSQL
本节总结自Bytebase的博客空间,虽然 MongoDB 在早期为 Infisical 提供了良好的服务,但当我们的产品场景不单单是托管服务时,它开始显示出不足之处。随着时间的推移,我们发现许多组织,特别是那些在合规和安全交叉点运营的组织,更喜欢自托管 Infisical 而非使用 Infisical Cloud;其他的有一些本地需求需要满足。
随着对自托管 Infisical 的需求增长,我们发现自己正在开发许多功能以减少学习如何自我托管 Infisical 所需的曲线,并且作为其中一部分,最终放弃了 MongoDB 转而支持 PostgreSQL。实际上,在能力和可用性方面和客户经常遇到 MongoDB 带来的限制问题,比如缺乏对事务、清理、云托管产品中版本一致性的支持,更不同提与 schema-less 数据库设计结构相关联的问题了。
以下是对其中一些挑战的详细解释:
1.配置数据库事务困难:使用 MongoDB,设置事务并不简单,因为它需要在集群模式下运行 MongoDB,并有各种配置开销;这使得客户要运行一个简单的 Infisical POC 变得极其困难,因为它需要生产环境下的 MongoDB 设置。对于处理高度敏感数据且数据完整性必须保证的产品来说,这是无法接受的。
2.缺少关系型特性:使用 MongoDB 后,我们失去了许多来自关系型世界的好功能,比如 CASCADE,当目标资源被删除时,可以删除其他表中所有被引用资源;这尤其令人痛苦,因为我们的数据非常依赖关系型。结果是,在我们旧代码库中采用了大量删除函数却从未能完全完成任务,并在 MongoDB 数据库中留下悬空资源。
3.云提供商支持不足:在 MongoDB 将许可更改为 SSPL 后,许多云提供商选择提供较老版本的 MongoDB。结果是,我们发现很难确保 Infisical 的功能可用性,除非是运行最新稳定版 MongoDB 的客户。
4.缺乏操作 MongoDB 的经验:由于更多人熟悉部署基于 SQL 的数据库,他们经常在扩展和正确配置 MongoDB 上遇到困难;这导致我们需要为客户提供的支持量不成比例地增加,特别是因为他们对 MongoDB 不熟悉。
出于以上以及其他更多原因,意识到使 Infisical 能够被世界各地的团队和组织更广泛接受所需的最重要功能,其实是需要全面迁移至更加通用的数据库。在寻找新的数据库时,我们首先列出了对我们最重要的几个方面:管理便利性(即包括配置、部署和扩展),内置事务支持,以及关系型功能。在讨论过程中,我们还考虑了是否应该构建自己的集成存储或寻求外部存储解决方案。
以下是每个选项的意义:
1.集成存储:我们可以将像 SQLite 这样的数据库系统直接打包到 Infisical 中,并采用水平复制策略来通过避免额外的网络跳转来减少延迟。在这个模型中,扩展系统意味着部署多个 Infisical 实例,并让它们通过某种共识算法(如 Raft)进行相互通信。虽然这看起来是一个极好的解决方案,因为客户不需要连接任何依赖项就能运行 Infisical,但执行此愿景所需的工具生态系统感觉还不够成熟,而且所需的工程努力也太强人所难了。
2.外部存储:我们可以简单地用 PostgreSQL 或 MySQL 等其他数据库替换 MongoDB,并使用其内置的扩展功能。尽管这个解决方案并没有完全消除使用 Infisical 时需要外部依赖项带来的摩擦,但我们认为它已经通过不再是 MongoDB,而带来了显著的优点。当涉及到支持一个或多个数据库时,我们认为支持多个会错过每种解决方案各自独特的优点;同时也会增加我们的工程开销。
经过慎重考虑,我们选择了 PostgreSQL。除了拥有活跃的社区、详尽的文档以及大量可用的解决方案和扩展外,我们最欣赏的是它开源的本质以及绝大多数云服务提供商都提供 PG的托管服务。这意味着 Infisical 的用户可以更容易地在任何云服务提供商上自行部署我们的平台,并将其与相应的托管 PostgreSQL 服务配对使用。此外,鉴于该数据库已被广泛采用,我们有信心用户在使用 Infisical 时操作起来会更加顺畅。
鉴于 Infisical 在客户基础设施中的关键作用,我们立即排除了有任何绝对停机时间的可能性。我们不得不做出妥协的部分是,在短暂的迁移窗口期间禁止写入操作(即客户无法创建或更新应用配置),以换取保证数据完整性。这种权衡似乎可以接受,因为客户主要从 Infisical 获取秘密信息。很少他们会每秒钟更新应用配置。
接下来,关于实际迁移操作,需要从 MongoDB 导出数据、仔细转换它,并将其重新插入到 PostgreSQL 中。当我们审计迁移序列时,面临着诸如确保各种树形结构从 NoSQL 正确地转化为它们关系型数据库等价物;这对于具有递归考虑因素的文件夹等数据结构特别敏感。我们还发现需要一种持久化方式来存储和映射 MongoDB 中与 PostgreSQL 中相同标识符;如果只依赖内存处理,考虑到我们处理的数据量之大,这是行不通的。最后我们选择使用 LevelDB 键值存储来协助标识符存储和查找操作。有了它,我们可以逐表地将数据移入 PostgreSQL 中。
最后准备进行迁移。在此之前,那些没有直接参与代码库重写的人员已经花了一个季度来改进 Infisical 的其他方面,包括进行前端更改、打维护补丁、扩展客户端功能,并编写更好的文档。现在我们所有人都重新聚集起来为迁移本身做准备,即用新的替换应用程序代码库,并将数据从 MongoDB 转移到 PostgreSQL。
作为准备工作的一部分,制定了一份详细的迁移清单和预期时间表。计划大致如下:
1.在迁移的几周前,我们会通过电子邮件和应用内横幅提前通知用户即将进行的数据库升级。我们将对平台上的每个功能流程进行彻底测试,并为迁移进行试运行。
2.迁移本身将在一个六小时的窗口期内发生,在此期间只允许对平台进行读取操作。在这个窗口期,我们会运行迁移脚本,把数据从 MongoDB 转移到 PostgreSQL,检查是否有数据丢失,并且如果成功就把 DNS 切换到新实例。当然,如果事情出现问题,我们已经备好了应急方案。
3.最后,在迁移之后,我们会解决任何残留问题,并开始推出 Infisical 和 PostgreSQL 一起工作的新文档。
幸运的是,迁移执行过程非常顺利,没有数据丢失,只有少数非关键功能出现故障;在接下来的 36 小时内解决了这些问题,并将对客户的影响降到最低。
在2024年年初完成迁移之后,我们观察到了许多好处:
1.平台的性能大幅提升,主要归因于对连接查询的优化。使用 MongoDB 时,平台经常需要进行效率低下的聚合查询和多次网络跳转以实现所需功能。例如,由于我们核心数据的关系特性,我们经常需要执行许多 $lookup 操作来模拟 SQL 中的连接;这些操作效率低下,并且通常需要我们相应地扩展数据库和应用实例。迁移到 PostgreSQL 后,我们避免了这些效率低下的操作,也使得数据库账单上的成本减少了 50%。
2.现在的平台采用更好的数据验证方式,在数据库层面而不是应用层面进行根源处理。由于 MongoDB 设计上没有 schema 约束,它依赖 Mongoose 框架定义数据类型、必填字段和验证规则。有了 PostgreSQL, 我们再也不会面临如果数据库被绕过 Mongoose 范围访问或修改时可能出现的数据不一致问题。
3.最后并且最重要的是,我们认为 Infisical 现在更容易自我托管,客户可以无需额外配置开销 (如处理 MongoDB 中启用事务功能所需的 replica sets) 就能进行 POC 测试。总体来说,考虑到手头目标、任务范围及其执行结果,我们认为这项举措非常成功。一旦我们有更多数据,我们计划在未来发布更具体的结果。
总的来说,考虑到手头的目标、任务的范围以及最终执行情况,我们认为这次的迁移非常成功。一旦有了更多的数据,我们打算在未来发布更具体的结果。