如何使用 MongoDB 创建高效、可扩展、多租户的数据层?

AJB*_*AJB 7 mongodb multi-tenant

我正在为我即将推出的 Project Mangement 应用程序(作为示例)研究架构,我正在寻求明确如何最好地设计 MongoDB 数据层,特别是多租户。该应用程序将有多个“子应用程序”(例如日历、任务列表、媒体、团队等),每个子应用程序将映射到数据库中的一个集合(中央数据库或它自己的项目数据库)。

数据库服务器 == 副本集。

问题

  1. 我应该使用一个巨大的、集中的数据库来存储所有应用程序数据,还是为系统上创建的每个项目创建一个单独的数据库?
  2. 如果我选择单独的数据库策略,考虑到数据库“自然地”分散在多台服务器上,从而“自然地”将负载分散到多台服务器上,是否不需要对数据层进行分片?该应用程序将包含告诉它哪个服务器访问任何给定项目的数据的逻辑。
  3. 为每个项目使用单独的数据库是否会给我更好的性能(假设要找到任何给定的文档,Mongo 只需要在单个项目数据库中搜索最多几千个文档,而在一个巨大的集中式数据库中可能会搜索数百万个文档)?
  4. 是否有可能减少 32M 的 MongoDB 数据库的最小占用空间?我已经阅读了--smallfiles 手册中的文档,但这并没有真正回答我的问题。这是最低要求吗?
  5. 如果任何给定的项目收到大量流量,并成为“嘈杂的邻居”,解决方案是否只是启动一个新的数据库服务器并将该项目移动到新服务器?还是将包含嘈杂邻居的数据库服务器分片以提高该服务器的性能是一种更好的方法?
  6. 在清理任何给定已删除项目的空间和/或“收缩包装”每个数据库以尽量减少其占用空间与存储在任何给定项目数据库中的实际数据量接近时,我有哪些“维护”问题?
  7. 对于必须在所有项目数据库中“推出”的数据“模式”的未来更改,我应该注意哪些问题?鉴于 Mongo 是“少模式”,假设如果我想向任何给定的集合添加一个新的“字段”,我只会在应用程序逻辑中这样做,而不必对数据库进行任何更新,是否正确?他们自己?
  8. 我将使用哪些 MongoDB“工具”来获取有关任何给定数据库服务器的当前“状态”的信息?
  9. 我应该注意的任何给定数据库服务器上可以容纳的数据库数量是否有任何限制?
  10. 单个数据库策略如何影响备份?在跨多个数据库服务器备份(到 S3 进行灾难恢复)多个数据库时,我应该注意什么问题?

应用程序堆栈

Ubuntu 12.04 LTS
Nginx
node.js
express.js
MongoDB
Run Code Online (Sandbox Code Playgroud)

当前的工作策略

我目前的工作策略是使用一个数据库来存储更高级别的“全局”数据,例如用户、通知、消息、使用情况和首选项。然后为系统上创建的每个项目创建一个新数据库。

由于许多原因,这似乎是理想的方法:安全性(每个数据库都有自己的凭据)、灾难性恢复(因为如果一个数据库服务器宕机,整个应用程序不会宕机)和性能(我认为,因为 Mongo 会搜索更少的文档以找到它正在寻找的文档)。

该应用程序将包含自动检测任何给定 DB 服务器上的可用空间并在下一个可用 DB 服务器上创建新 Project 数据库的逻辑。

根据MongoHQ 提供的这篇文章,这是“最佳”策略,尽管它会消耗大量存储空间。特别是因为每个数据库即使在空的情况下也占用 32M。如果您提供的“免费增值”应用程序获得了 Techcrunch 的支持,那么使用 MongoHQ 之类的服务会变得非常昂贵。

因此,在 ProjectManager 在系统上有三个项目的情况下,我的数据层将如下所示:

ProjectManager
  Users
  Notifications
  Messages
  Usage
  Preferences

Project01
  Calendar
  Tasks
  Media
  Team

Project02
  Calendar
  Tasks
  Media
  Team

Project03
  Calendar
  Tasks
  Media
  Team
Run Code Online (Sandbox Code Playgroud)

上述每个 ProjectXX DB 都是很小的。每个最多存储约2000-3000个文档。

提前感谢您的任何见解。

sys*_*138 7

需要牢记以下几点:

  • 大规模有效的方法在小规模时并不总是有效。
  • 认为大规模需要的通常并不是您达到该规模时实际需要的。
  • 最佳性能是特定于应用程序的,而不是通用的。最适合您的应用的可能并不适合我的应用。
  • 所有无模式意味着数据库系统不会在您更改它时与您对抗。您的应用程序代码仍然有一个架构,您必须围绕它进行设计。
    • 添加新字段?Mongo 不在乎,只有您的应用程序逻辑在乎。
    • 将字段从单值更改为多值?蒙哥不在乎。但是您代码中的函数肯定会。您需要构建数据迁移路径,或设计您的代码来处理这两种情况。
  • 当您需要扩展服务器占用空间时,操作限制(例如您可以负担得起的 AWS 实例)将推动。

鉴于此,现在在构建系统时需要遵循一些设计模式。根据您在此过程中学到的知识,这些项目将使以后的扩展更容易。

立即分片
这迫使您开始考虑好的分片键,因为分片键是您的非架构的一部分,很难在以后更改。此时您不是为了性能而进行分片,而是现在进行分片以确保您的代码可以处理它并在几个里程碑的道路上引导性能问题。

现在工程师多数据库支持
如果您预计需要多个数据库,甚至多个 Mongo 数据库集群,那么在早期阶段构建数据本地性将易于稍后放置。现在它可能都在一个集群中,并且所有项目/任务/日历/用户都在相同的三个 MongoD 实例中,但是当您了解到 Calendars 数据库正在减慢一切并需要移动到 SSD 支持的实例时,您可以这样改变就容易多了。

数据库压缩仅在某些情况下很重要
因为数据库文件本身被映射为 2GB 的数据库文件包含 200MB 的数据库,只要您的存储子系统能够很好地处理随机 I/O,实际上并不会影响性能。此外,压缩会使节点脱机一段时间,这可能会对正常操作产生重大影响。此外,如果您从不删除文档,则不必担心压缩。

了解分离的集合和分离的数据库会带来什么
同一个数据库中的集合共享相同的数据库锁,它们一直在随着 MongoDB 的每个版本稳步减少。
同一实例中的数据库彼此共享 I/O,并且仍然存在极少数全局锁定事件。

索引很重要
如果您没有足够的 RAM 来至少将索引保存在内存中,那么性能将非常糟糕。根据您获得的大小,您最终可能会分片或拆分集合,以获得再次适合 RAM 的索引。这是多租户可能成为问题的一个领域;如果你在一个集合中有几个大的、未使用的租户,所有这些索引都必须保存在 RAM 中才能使整个系统运行。如果您基于租户拆分集合,那么未使用的索引可以在几乎没有损失的情况下被调出。