您可以使用MongoDB Search实现多租户,以便应用程序的单个实例为多个租户提供服务。本页介绍专门应用于MongoDB Search 的设计建议,用于结构化数据和MongoDB Search 索引,以便在保持租户隔离性的同时安全扩展。
重要
本指导假设您可以在单个 VPC中共置租户。如果需要严格的网络隔离性,则必须为每个租户维护单独的项目。
选择策略
根据您的隔离性需求、扩展目标和写入负载要求选择策略。最常见的策略是:
所有租户的单个集合 - 建议对大多数工作负载使用此策略。
每个租户一个数据库 - 此策略提供高度隔离性,但会增加索引计数。
每个租户一个集合 — 不建议对MongoDB Search工作负载使用此策略。
适用于所有租户的单一集合(推荐)
我们建议应用“所有租户使用一个集合”策略。在此架构中,您将所有租户数据存储在单个数据库内的单个集合中。您可以通过在每个文档中包含 tenant_id字段来区分租户。此字段可以是租户的任何唯一标识符,例如 UUID 或租户名称。
这种集中式方法具有以下优点:
减少索引数量
由于所有租户数据都存储在一个集合中,因此您只需要一个为所有租户提供文档的索引。可以避免达到集群资源限制。示例,您可以在单个索引中包含
tenant_id和其他共享或租户特定的字段。简化维护操作
由于只有一个集合存储所有数据,因此您不必维护多个集合或跨多个数据库扩展资源。您还可以简化备份、分片和复制操作,因为您只需针对单个数据库中的单个集合。
高效处理查询
您可以使用
$search.compound.filter子句中的 等于操作符在查询中提供tenant_id字段作为过滤器。注意
查询结果将仅包含来自匹配租户的文档,从而防止数据跨租户泄漏。
如果您托管的租户股票相似的访问权限模式和资源大小,则此策略还可以使Lucene索引字段数保持较低水平。
重要
当每个租户都有较高的写入负载时,将所有租户并置到单个集合中可能会导致写入争用。在这种情况下,可以考虑将写入次数最多的租户拆分到单独的集合中,以便将写入负载分布到更多的根本的资源。
如果您的大型租户具有独特的资源或索引需求,请使用视图:
单独索引。在视图上创建MongoDB Search索引。
这样,您就可以为大型租户自定义索引定义,而不会影响其他租户使用的共享索引。所有其他租户都可以使用单个索引。
大量索引会在基础集群上产生大量负载,并可能扰乱您的工作负载。单个集群上的搜索索引硬性限制为 2,500。但是,集群可以支持的索引数量取决于集群层和工作负载。由于索引数量少得多,
M10等较小的集群层可能会出现性能下降或内存不足错误的情况。从少量索引开始,并在扩展时监控集群的资源使用情况。
If you currently apply the one collection per tenant strategy, we recommend scaling up the base tier to prevent increased replication lagor OOM errors due to resource contention from ahigh number of indexes. We also recommend migrating to the one collection for all tenants strategy.
处理高写入租户
如果特定租户有大量写入负载,则可能会导致共享集合发生争用。我们建议您仅将流量最大的租户移动到单独的集合中,以分配 I/O 负载。
处理唯一需求(视图)
如果某个租户需要唯一索引或明显大于其他租户,请使用MongoDB视图:
每个租户一个数据库
在每租户数据库设置中,每个租户都包含自己的数据库。此设置会隔离租户数据,但也会成倍增加集群中的索引数量。如果支持所有租户的数据库超过 2,500,则集群可能会达到 2,500-索引上限。
警告
大量索引会在基础集群上产生大量负载,并可能扰乱您的工作负载。单个集群上的搜索索引硬性限制为 2,500。但是,集群可以支持的索引数量取决于集群层和工作负载。由于索引数量少得多,M10 等较小的集群层可能会出现性能下降或内存不足错误的情况。从少量索引开始,并在扩展时监控集群的资源使用情况。
每个租户一个集合(不推荐)
每个租户的集合策略将每个租户映射到共享数据库中自己的集合。维护每个集合的索引的开销可能会导致:
复制延迟增加
由于资源争用而导致的 OOM 错误
基础层级不稳定
我们不建议对MongoDB Search 使用这种策略,除非租户具有非常可预测的轻量级工作负载。如果您当前使用此策略,迁移到所有租户的一个集合策略。
管理索引字段
请考虑以下建议来管理索引字段:
多租户应用程序通常需要可搜索、排序、分面和筛选的自定义每租户字段。使用 typeSet 动态索引路径的子字段,以便MongoDB Search 自动选取新字段,而无需重建完整索引。避免对这些字段进行静态索引,因为这样做会触发重建,从而增加 CPU 压力并消耗高达 2 倍索引的磁盘空间。
注意
字段过多的风险
Lucene index performance can degrade if there are more than 1000 distinct fields. You can monitor the number of unique fields in the MongoDB Search index in the MongoDB Search metrics. If you need to support one thousand or more fields, we recommend the following:
使用视图将租户子集分离到单独的索引中,以便单个Lucene索引中存在的不同字段数保持在 1,000 以下。
限制单个租户可以添加的字段数量。
如果使用属性模式为每个租户存储不同的密钥,我们建议您执行以下操作:
使用视图展平嵌入式文档数组。
在视图上创建MongoDB搜索索引,并将其存储在磁盘上。
如果不展平文档数组,则需要使用 embeddedDocuments操作符查询(类似于$elemMatch)来查询属性,这比查询展平结构的性能要低。