PHP失去mongoDB游标,尽管长时间超时


PHP loses mongoDB cursor despite long timeouts

我正在运行这样一个长mongoDB查询:

foreach($xyz->find(...)->timeout(24 * 60 * 60 * 1000)->maxTimeMS(24 * 60 * 60 * 1000) as $document) {
    ...
}

但是,尽管客户端和服务器有24小时的超时,脚本在几分钟后以MongoCursorException退出:

localhost:27017:无法在集合xyz上找到游标

我在PHP 5.4与v1.6.10 mongoDB驱动程序。DB版本为mongoDB 3.0.4。PHP将连接到mongos实例,集合xyz将被分片。

知道是什么导致了这个异常吗?

我不得不说,我也有类似的经历,我有一个集合,我通过

$items  = $col -> find(['data' => 'OK']);
$items->timeout(-1);
$items->maxTimeMS(3600*1000);

但步行后通过

foreach($items as $item)
{
   ///... processing
}

大约12 - 15分钟后,我得到相同的错误

could not find cursor over collection

在集合中,大约有150000条记录,有趣的事实是,错误总是在处理了123479条记录之后出现,而不管第123480条记录的内容如何,也不管处理这些记录所花费的时间(处理记录所需的时间可能因内容而异)。

由于我找不到任何错误的原因,经过几次尝试改进mongo设置,包括升级PHP驱动程序,我现在分批进行整个过程,以防止丢失游标。它工作得很好,但是,我想知道更干净的解决方案

似乎有更多的超时是PHP(目前)不支持的。其中之一是maxIdleTimeMS:

连接在被删除和关闭之前可以在池中保持空闲的最大毫秒数。

在我的例子中,由于数据库有时很忙,这个长时间运行的查询空闲的时间太长,所以它的游标在服务器端被丢弃了。

设置这个参数会有帮助,但由于它不可用,我发现解决问题的方法是减少批处理大小:

$cursor->batchSize(-20)

在本例中,每批在服务器和客户端之间最多传输20个文档。这减少了连接空闲时间过长的可能性。当然,确切的值取决于数据库的负载、处理每个文档所需的时间等。

我也有同样的问题。我已经尝试了上一个版本的两个驱动程序,

    PHP 5.6 x86非线程安全(Windows)
  • https://pecl.php.net/package/mongo版本1.6.14
  • https://pecl.php.net/package/mongodb版本1.1.9

find 方法返回游标。我不确定这是如何工作的,但这个光标没有包含所有的文档。连接中断后,需要请求mongo获取下一个ans。

我的解决方案是使用方法MongoDB'Driver'Cursor (Driver MongoDB)的toArray

返回一个包含所有文档的数组。我有一个批处理,可以处理超过10万个文档,没有问题。