我正在运行这样一个长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。
我的解决方案是使用方法MongoDBDriverCursor (Driver MongoDB)的toArray
返回一个包含所有文档的数组。我有一个批处理,可以处理超过10万个文档,没有问题。