Mongodb — агрегат и batchSize — курсор не найден через 1 минуту

У меня необычная проблема тайм-аута Mongodb — я получаю cursor not found ошибка, хотя тайм-аут 10 минут не был достигнут.

Мой env:

  • Убунту 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 дня я получаю cursor not found ошибка на foreach ($userItemsPage as $item_user) линия.
То, что вызывает у меня головную боль, это то, что я вижу:

ОБЪЕМЫ ИСПОЛЬЗОВАНИЯ ПОЛЬЗОВАТЕЛЯ

регистрируйте строку каждые 50 секунд (45 секунд, чтобы повторить результаты по 10 тысяч, и 5 секунд, чтобы выполнить массовую вставку), а затем строку ошибки через 1 минуту после этого.
Каждый пользовательский анализ занимает от 1 до 120 минут. Я не изменил размер пакета по умолчанию для 101 документа.

Поэтому я изо всех сил пытаюсь понять, где скрывается ошибка тайм-аута.

Я прошел превосходный ответ @Danziger здесь (MongoDB — Ошибка: команда getMore не выполнена: курсор не найден) но это кажется не связанным с моим сценарием.

И есть еще один связанный, но без ответа вопрос (MongoDB — PHP — MongoCursorException «Курсор не найден»)

Спасибо,

1

Решение

Хорошо, я думаю, что понимаю, что происходит сейчас, find() а также aggregate() вести себя по-другому в отношении batchSize,

Найти (https://docs.mongodb.com/manual/reference/method/cursor.batchSize):

найти

Определяет количество документов, возвращаемых в каждой партии

заполнитель:

указать начальный размер пакета для курсора

Так с aggregate()указание batchSize для последующих пакетов выполняется на возвращенном курсоре, а не в команде агрегации. Однако это не возможно в PHP — у нас нет такого же уровня контроля над объектом курсора. Это означает, что агрегацией batchSize нельзя управлять в PHP. Я поднял билет на это с прекрасными людьми в Монго (https://jira.mongodb.org/browse/PHPLIB-312).

В моем случае это проявилось в том, что Монго вернул мне большую партию (~ 130 тыс. Документов), обработка которой могла занять> 10 минут. Я вставлял документы по 10 тыс. Одновременно, но это не означало, что я одновременно читал партии по 10 тыс. Из монго.

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector