0

在执行慢速查询时,我们在 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 最多打开 800 个与 MongoDB 的连接(根据日志,通常我们有 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. 我应该在连接和查询上设置超时来解决这个问题还是别的什么?

我问这个的原因是因为我们的网站增长非常快,我们预计未来会有更多的流量和 MongoDB 负载。

提前非常感谢!

4

1 回答 1

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并找到适当的_idwhere activeis falseactivetrue在相同的原子操作中更新。只有在取回此锁定文档后,它才能继续执行该group命令。其他找不到锁文件的PHP进程(因为active不会false) 可以被指示休眠一段时间、返回陈旧数据或中止 Web 请求。

于 2013-09-04T18:22:42.197 回答