【发布时间】:2018-01-29 01:28:17
【问题描述】:
我有一个不寻常的 mongodb 游标超时问题 - 即使没有达到 10 分钟的超时时间,我也会收到 cursor not found 错误。
我的环境:
- ubuntu 14.04 LTS
- PHP 7.1.13
- libmongoc 捆绑版本 1.8.2
- MongoDB 扩展版本 1.3.3
- mongodb/mongodb 1.2.0
这是一些代码。简而言之,我对数百万用户进行循环,对每个用户执行一次大型聚合,用游标遍历结果,然后运行一堆批量更新。
<?php
/**
* THE AIM IS TO PERFORM A BIG AGGREGATION ON AN ENTIRE COLLECTION, MASSAGE THE RESULTS, AND WRITE INTO A PERMANENT COLLECTION.
*
* THE AGGREGATION IS BIG, SO IT WRITES TO DISK, AND WE ACCESS WITH A CURSOR.
*
* IN ORDER TO IMPROVE PERFORMANCE, WE BULK-UPSERT INTO THE PERMANENT COLLECTION ON EVERY 10k DOCUMENTS.
*
*/
class Analytics
{
const MAX_CURSOR_PAGE_SIZE = 10000;
public function performAnalytics($arr_user_ids)
{
foreach ($arr_user_ids as $item_user_id)
$this->performUserAnalytics($item_user_id->id);
}
private function performUserAnalytics($userId)
{
// AGGREGATION QUERY
$userItemsPage = $this->getUserItemsPage($userId);
// BULK UPSERT
$arrItemOps = [];
foreach ($userItemsPage as $item_user)
{
array_push($arrItemOps, [
'updateOne' => [
[ 'my_key' => $item_user->_id, ],
[ '$set' => [ 'item_ids' => $item_user->item_ids ] ],
[ 'upsert' => true ]
]
]);
// BULK-UPSERT FOR PERFORMANCE
if(count($arrItemOps) > self::MAX_CURSOR_PAGE_SIZE)
{
Log::info("BULK-UPSERTING USER ITEMS");
$permanent_collection->bulkUpsert($arrItemOps);
$arrItemOps = [];
}
}
// FINAL BULK-UPSERT
if(count($arrItemOps) > 0)
$permanent_collection->bulkUpsert($arrItemOps);
}
// BIG AGGREGATION
private function getUserItemsPage($userId)
{
return $items_collection->aggregate([
[
'$match' => [
'user_id' => $userId
]
],
[
'$group' => [
'_id' => '$user_id',
'item_ids' => [
'$addToSet' => '$item_id'
]
]
]
],
[ 'allowDiskUse' => true ]);
}
}
代码运行大约需要 2 天。 1.3 天后,我在 foreach ($userItemsPage as $item_user) 行上收到 cursor not found 错误。
让我头疼的是,我看到了一个:
批量替换用户项目
每 50 秒记录一行(45 秒循环超过 10k 个结果,5 秒循环插入),然后在 1 分钟后出现错误行。 每个用户分析需要 1-120 分钟。我没有修改 101 个文档的默认批量大小。
所以我很难看到超时错误隐藏在哪里。
我在这里查看了@Danziger 的出色回复(MongoDB - Error: getMore command failed: Cursor not found),但这似乎与我的情况无关。
还有另一个相关但未回答的问题 (MongoDB - PHP - MongoCursorException 'Cursor not found')
谢谢,
【问题讨论】:
-
看到零星的崩溃,这次是在 5 小时后,在不同的用户上
-
我用 'getMore' 命令看不到很多 mongod 日志行。我怀疑 mongo 可能没有使用 101 作为默认批量大小,而只是 initial 批量大小。也许这是
find()和aggregate()之间的区别
标签: php mongodb timeout cursor aggregation-framework