我的应用程序有一个用户集合。集合中的每个文档平均大小约为 0.04 MB。在最坏的情况下,文档可能会稍微超过 0.1 MB。不用说,这些都是小文件。然而,每个文档可能有超过 1000 个字段。
此用户集合有 3 种类型的读取查询:
第三种查询速度慢。所以计划是分而治之,即将 User 集合划分为分片,每个分片平均有 10,000 个文档。因此,如果我的应用程序扩展到 1 亿用户,则将有 10,000 个分片,每个分片包含该用户集合的大约 10,000 个文档。为了确保均匀分布,_id 将用作分片键。通过电子邮件使用 findOne 的唯一时间是在用户登录期间,这种情况很少发生。 _id 的 findOne 将被定位。
第三种类型的查询,通过任意过滤器组合findMany,将是分散和聚集。这正是我们的意图。扩展第三种查询类型的唯一方法是分而治之。
问题:
我正在阅读您的问题和您提出的策略,您的想法给我留下了深刻的印象。您提出的解决方案似乎很可靠,但有一些事情您应该注意。
这个
findMany
用户通过一组过滤器起作用,但这取决于数据的性质以及来自这些字段的任意组合的过滤器。
我认为,如果过滤器具有高度选择性并且可以有效地缩小结果集范围,那么分散和聚集方法应该具有相当好的扩展性。但是,如果过滤器的选择性不够,或者导致跨多个分片检查大量文档,您可能会因从多个分片收集和处理数据的开销而遇到性能问题。
不要忘记分析您的应用程序将执行的查询类型,以确保分片策略与预期工作负载保持一致。
此外,请考虑优化查询模式和索引,以最大程度地减少需要跨分片检查的文档数量。
好吧,我想到的下一件事是您提出的有关 mongos 协调 10,000 个节点之间通信的开销的担忧。
mongos 协调分片之间通信的开销可能很大,我知道这一点是因为我在一个大型项目中遇到过这个问题。尤其是有大量碎片的情况下。
我通过保持各个分片大小相对较小并且查询具有针对性来解决了这个问题。这使得管理费用变得可控。我还被迫优化查询、适当索引并利用缓存机制,这也有助于减轻这种开销。
// to check shard distribution and balancing status
sh.status();
// to manually rebalance shards if needed
sh.rebalanceCollection("database.collection");
/*
Hey man, don't forget to regularly monitor the
distribution of data across shards and manually
rebalance them if necessary to ensure even data
distribution and optimal performance.
*/
接下来我想谈谈索引,但我知道你已经知道了。
索引。你做得还不够。索引是解决分布式计算中嵌入的性能问题的最快方法。
分析每次调用执行的典型查询,并创建有效覆盖这些查询涉及的字段的索引。
稀疏索引对于仅针对文档中字段子集的查询也很有用。
不要忘记随着应用程序的发展定期检查和优化索引,以确保所有分片的最佳查询性能。
// you can create indexes on fields you suspect will
// be used commonly
db.users.createIndex({ field1: 1 });
db.users.createIndex({ field2: 1 });
最后一点对我来说是个人的,因为我因为忽视它或至少没有正确实施它而付出了高昂的代价。
MONITORING
您必须持续监控和优化,才能维持分片集群的性能和可扩展性。
请务必跟踪关键性能指标:所有分片的查询延迟、吞吐量和资源利用率等。然后,您可以使用这些数据来识别性能瓶颈、热点和优化领域。
定期审查和分析查询执行计划、索引使用情况和系统指标,以确定改进的机会。您还应该随时了解 MongoDB 分片的更新和最佳实践,因为 Mongo 团队始终在对系统进行改进。这是给你的一点东西。您可能需要也可能不需要它。
// Enable profiling to capture query performance data
db.setProfilingLevel(2);
// Analyze slow queries to identify performance
//bottlenecks
db.system.profile.find({ millis: { $gt: 100 }
}).sort({
ts: -1 }).limit(10);
好的。不确定这是否有帮助,但这些是我的想法。