在进行MongoDB分片的一些初步测试时,我希望并且预计在一个分片/机器上执行仅查看一个数据块的查询的时间将随着更多数据的加载而保持相对恒定。但我发现了一个显着的放缓。
一些细节:
对于我的简单测试,我使用两台机器进行分片并尝试对类似集合进行查询,其中包含200万行和700万行。这些显然是非常小的集合,甚至不需要分片,但我很惊讶已经看到只有一个块的查询显着一致的减速。查询包括分片键,用于从10到100000行的结果集,并且我测量了滚动整个结果集所需的总时间。另一件事:由于我的应用程序实际上需要的数据量远远超过RAM,因此所有查询都基于冷缓存进行定时。
知道为什么会这样吗?还有其他人观察到相同或相互矛盾的结果吗?
进一步细节(由Theo提示):
对于此测试,行很小(5列包括_id),键不是基于_id,而是基于多值文本列,几乎总是出现在查询中。
命令db.printShardingStatus()显示有多少块以及用于分割块范围的确切键值。对于此数据集,平均块包含超过100,000行,并且对键值拆分的检查将验证测试查询是否正在命中单个块。
为了这个测试的目的,我只测量读数。没有插入或更新。
更新
经过一些额外的研究,我相信我确定了减速的原因:MongoDB块是完全合乎逻辑的,其中的数据并不是物理上位于一起(来源:Kristina Chodorow的“Scaling MongoDB”)。这与Oracle和MySQL等传统数据库中的分区形成对比。这似乎是一个重要的限制,因为分片将随着分片/机器的添加而水平缩放,但在垂直维度上不太好,因为数据被添加到具有固定数量分片的集合中。
如果我理解正确的话,如果我有10个分片/机器的十亿行分片的1个集合,即使是只触及一个分片/机器的查询仍在查询大量的1亿行集合。如果分片键的值恰好位于磁盘上,那么这可能没问题。但如果没有,而且我需要多行(例如1000s),那么这似乎可能会导致很多I / O问题。
所以我的新问题是:为什么不在物理上组织MongoDB中的块以实现垂直和水平可伸缩性?
答案 0 :(得分:1)
是什么让你说查询只涉及一个块?如果结果范围高达100 000行,那听起来不太可能。一个块最大64 Mb,除非你的物体很小,许多不适合。 Mongo最有可能拆分你的块并分发它们。
我认为您需要告诉我们有关您正在做什么以及数据形状的更多信息。你在同一时间查询和加载吗?你说大块的时候是什么意思吗?你的分片键不是_id
吗?在查询数据时是否进行了任何更新?
在Mongo中有两个主要因素:全局写锁和它使用内存映射文件。内存映射文件意味着你必须考虑你的使用模式,而全局写锁会使页面错误受到严重损害。
如果你查询各地的东西,操作系统将很难进出内容,如果你的对象很小,这可能会特别有害,因为只需要加载整个页面来访问一小块,很多RAM将被浪费。如果你正在进行大量的写操作来锁定读取(但通常写得不那么糟糕,因为写操作相当顺序) - 但如果你正在进行更新,你可以忘记任何类型的性能,更新会阻塞整个数据库服务器大量的时间。
在您运行测试时运行mongostat
,它可以告诉您很多(运行mongostat --discover | grep -v SEC
以查看所有分片大师的指标,不要忘记包含--port
如果你的mongos
没有在27017上运行。)
解决您的更新中的问题:如果Mongo确实将块保持在一起,那将是非常好的,但事实并非如此。其中一个原因是分片是mongod
之上的一个层,而mongod
并不完全知道它是一个分片。这是配置服务器和mongos
进程知道分片键和存在的块。因此,在当前体系结构中,mongod
甚至没有将块保持在磁盘上所需的信息。问题更深层:Mongo的磁盘格式不是很先进。它仍然(从v2.0开始)没有在线压缩(虽然压缩在v2.0中变得更好),它无法压缩碎片数据库并仍然提供查询。遗憾的是,Mongo还有很长的路要走,因为它能够满足你的想法。
此时您可以做的最好的事情是确保按顺序写入数据,以便按顺序写入数据块。如果您事先创建所有块,这可能会有所帮助,因此平衡器不会移动数据。当然,只有事先获得所有数据,这才有可能,而这似乎不太可能。
答案 1 :(得分:1)
免责声明:我在Tokutek工作
所以我的新问题是:为什么不在物理上组织MongoDB中的块以实现垂直和水平可伸缩性?
这正是在TokuMX中完成的工作,它是MongoDB的替代服务器。 TokuMX使用具有高写入吞吐量和压缩的分形树索引,因此数据不是将数据存储在堆中,而是clustered with the index。默认情况下,分片键是群集的,因此它完全按照您的建议执行,它通过确保所有文档按磁盘上的分片键排序来物理地组织块。这使得分片上的范围查询快速,就像在任何聚簇索引上一样。