执行慢速查询时,我们在MongoDB PHP驱动程序(v1.3)中遇到了半奇怪的行为。当请求缓慢时,驱动程序似乎保持打开连接,我不完全理解为什么。也许你们这里有一些建议。
首先是一些事实:
每天一次Memcache记录过期并且慢速查询完成。这导致PHP向MongoDB开放多达800个连接(通常我们根据日志有10个开放连接)。我们的网站几乎完全是Memcached,因此我们的数据库没有任何其他重要负载。 800个开放连接使网站首先有30秒的加载时间,并在以后抛出几种类型的MongoExceptions(太多的连接/套接字异常)。
这是一个丑陋的查询与group by。为了清楚起见,我们理解这个查询是缓慢且愚蠢的,我们今天正在删除此查询。目前尚不清楚为什么它搞砸了整个网站。我们使用Doctrine作为抽象层,但根据日志,这是对200,000文档数据库(每个文档3个字段:id / product / date)的实际查询:
{"group":true,"keys":{"product":1},"initial":{"count":0},"reduce":"function (obj, prev) { prev.count++; }","options":[],"db":"Orders","collection":"History"}
查询完成后,其结果将写入Memcache 24小时。所以所有新请求都是从Memcache获取的,而不是从MongoDB获取的。但是,它仍然坚持800个连接,问题并没有自行解决,网站在一段时间后不再响应。打开这800个连接大约需要10分钟。
感觉就像典型的竞争条件。查询只是感觉不够重,实际上在此服务器上导致此负载的竞争条件。我的意思是,它感觉不应该。
好的,问题是:
原因我问这是因为我们的网站增长速度非常快,我们预计未来会有更多的流量和MongoDB负载。
提前多多感谢!
答案 0 :(得分:1)
鉴于您正在调用group
命令而不是执行基本读取查询,您可能还在与MongoDB 2.2中的JavaScript解释器进行斗争。直到2.4,JavaScript解释器才得到增强,以支持并发执行。如果这些组操作中的每一个都需要JS评估(至少对于reduce
函数),那么您正在寻找广泛的资源匮乏。
我对“太多连接”例外没有任何解释。即使是800个并发连接也远远低于MongoDB的20,000个限制(注意:SERVER-8943中的2.6被删除了。)
重构应用程序并避免group
竞争条件的一个想法是使用单个文档作为PHP进程的锁,以重新计算结果并重新填充缓存。使用findAndModify
,您可以拥有一个包含字符串_id
的文档(例如“Order.History group”)和另一个active
字段。当PHP进程获得缓存未命中并需要重新计算结果时,它可以首先尝试执行findAndModify
并找到_id
active
false
所在的active
,更新在同一个原子操作中true
到group
。只有在获得此锁定文档后,才能继续执行active
命令。其他无法找到锁文档的PHP进程(因为false
将不是{{1}})可能会被指示暂时休眠,返回陈旧数据或中止Web请求。