PHP MongoDB驱动程序在慢查询时打开许多连接

时间:2013-09-04 09:53:37

标签: php performance mongodb race-condition high-traffic

执行慢速查询时,我们在MongoDB PHP驱动程序(v1.3)中遇到了半奇怪的行为。当请求缓慢时,驱动程序似乎保持打开连接,我不完全理解为什么。也许你们这里有一些建议。

首先是一些事实:

  • 网站和数据库在单个Ubuntu 13.04服务器上运行
  • 服务器是高端8核16GB RAM服务器
  • MongoDB v2.2.4
  • 网站运行PHP 5.4
  • Apache 2作为Web服务器
  • PHP Mongo驱动程序1.3.x(应该是最新的1.3)
  • 网站使用Doctrine ODM
  • 网站随时有大约50到100个并发用户
  • ulimit打开文件(ulimit nofile)= 64000

每天一次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分钟。

感觉就像典型的竞争条件。查询只是感觉不够重,实际上在此服务器上导致此负载的竞争条件。我的意思是,它感觉不应该。

好的,问题是:

  1. 为什么PHP会继续打开这么多连接?
  2. 为什么MongoDB不能处理这个问题(这不应该是一个大问题,对吗?)
  3. 关于我们应该做什么的任何其他建议?
  4. 我应该在连接和查询上设置超时来解决这个问题还是其他问题?
  5. 原因我问这是因为我们的网站增长速度非常快,我们预计未来会有更多的流量和MongoDB负载。

    提前多多感谢!

1 个答案:

答案 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,更新在同一个原子操作中truegroup。只有在获得此锁定文档后,才能继续执行active命令。其他无法找到锁文档的PHP进程(因为false将不是{{1}})可能会被指示暂时休眠,返回陈旧数据或中止Web请求。