Mongodb - 聚合和batchSize - 1分钟后找不到光标

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mongodb - 聚合和batchSize - 1分钟后找不到光标相关的知识,希望对你有一定的参考价值。

我有一个不寻常的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

这是一些代码。简而言之,我循环了数百万用户,为每个用户执行大型聚合,使用游标循环结果,然后运行一堆批量upsert。

<?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天后,我在cursor not found线上得到foreach ($userItemsPage as $item_user)错误。令我头疼的是我看到了:

BULK-UPSERTING用户项目

每50秒记录一次(45s循环超过10k结果,5s循环upup),然后是1分钟后的错误行。每个用户分析需要1-120分钟。我没有修改101个文档的默认批量大小。

所以我很难看到超时错误隐藏在哪里。

我在这里完成了@Danziger的优秀回复(MongoDB - Error: getMore command failed: Cursor not found)但似乎与我的情景无关。

还有另一个相关但没有答案的问题(MongoDB - PHP - MongoCursorException 'Cursor not found'

谢谢,

答案

好吧,我想我明白现在发生了什么,find()aggregate()batchSize方面表现不同。

查找(https://docs.mongodb.com/manual/reference/method/cursor.batchSize):

Find

指定每批中要返回的文档数

Aggregate

指定游标的初始批处理大小

因此,使用aggregate(),为返回的游标指定后续批处理的batchSize,而不是在聚合命令中。但是在PHP中这是不可能的 - 我们对游标对象没有相同级别的控制。这意味着无法在PHP中控制聚合batchSize。我和mongo(https://jira.mongodb.org/browse/PHPLIB-312)的优秀人员共同筹集了一张门票。

在我的情况下,这表现为mongo给我一大批(约130k文件),可能需要> 10分钟来处理。我一次插入10k文件,但这并不意味着我一次从mongo读取10k批。

以上是关于Mongodb - 聚合和batchSize - 1分钟后找不到光标的主要内容,如果未能解决你的问题,请参考以下文章

mongodb Aggregation聚合操作之$facet

mongodb Aggregation聚合操作之$sort

Mongodb的聚合和管道

MongoDB——聚合管道

MongoDB——聚合管道

Mongodb中数据聚合之聚合管道aggregate