Что такое Курсор в MongoDB?

Мы обеспокоены в конечном итоге происходит cursor not found exceptions для некоторых запросов морфия asList и я нашел подсказка на SO, что это может быть довольно чахоточный памяти.

теперь я хотел бы узнать немного больше о фоне: может ли sombody объяснить (на английском языке), Что такое Курсор (в MongoDB) на самом деле? Почему его можно держать открытым или не найти?


документация определяет курсор как:

указатель на результирующий набор запроса. Клиенты могут перебирать курсор для получения результатов. По умолчанию время ожидания курсоров после 10 минут бездействия

но это не очень показательно. Возможно, было бы полезно определить batch для результатов запроса, поскольку в документации также указано:

сервер MongoDB возвращает результаты запроса пакетами. Размер пакета не будет превышать максимальный размер документа BSON. Для большинство запросов, первый пакет возвращает 101 документ или только достаточно документов, чтобы превысить 1 мегабайт. Последующий размер пакета-4 мегабайта. [...] Для запросов, включающих операцию сортировки без индекса, сервер должен загрузить все документы в память для выполнения сортировки перед возвратом результатов.

Примечание: в наших запросах мы вообще не используем операторы сортировки, но и нет limit и offset.

2 ответов


Я ни в коем случае не эксперт mongodb, но я просто хочу добавить некоторые наблюдения от работы в системе среднего размера mongo за последний год. Также Спасибо @xameeramir за отличную прогулку о том, как работают курсоры в целом.

причин исключения "потерянный курсор" может быть несколько. Один, который я заметил, объясняется в этом ответе.

курсор живет на стороне сервера. Он не распространяется по набору реплик, но существует на экземпляре, который является первичным в время творения. Это означает, что если другой экземпляр берет на себя роль первичного, курсор будет потерян для клиента. Если старый первичный все еще работает и вокруг него, он все еще может быть там, но бесполезен. Думаю, через какое-то время его убирают. Поэтому, если ваш набор реплик mongo нестабилен или у вас есть шаткая сеть перед ним, вам не повезло при выполнении каких-либо длительных запросов.

Если полное содержимое того, что курсор хочет вернуть, не помещается в память на сервер запрос может быть очень медленным. ОЗУ на серверах должно быть больше, чем самый большой запрос, который вы запускаете.

всего этого можно частично избежать, разработав лучше. Для случая использования с большими длительными запросами вы можете быть лучше с несколькими меньшими коллекциями баз данных вместо большого.


найти() и курсоры в узел.водитель на JS

var MongoClient = require('mongodb').MongoClient,
assert = require('assert');

MongoClient.connect('mongodb://localhost:27017/crunchbase', function (err, db) {
    assert.equal(err, null);
    console.log("Successfully connected to MongoDB.");

    var query = {
        "category_code": "biotech"
    };

    db.collection('companies').find(query).toArray(function (err, docs) {
        assert.equal(err, null);
        assert.notEqual(docs.length, 0);

        docs.forEach(function (doc) {
            console.log(doc.name + " is a " + doc.category_code + " company.");
        });

        db.close();
    });
});

обратите внимание, что вызов .toArray делает приложение для извлечения всего набора данных.

var MongoClient = require('mongodb').MongoClient,
assert = require('assert');

MongoClient.connect('mongodb://localhost:27017/crunchbase', function (err, db) {
    assert.equal(err, null);
    console.log("Successfully connected to MongoDB.");

    var query = { "category_code": "biotech" };

    var cursor = db.collection('companies').find(query);

    cursor.forEach(
        function (doc) {
            console.log(doc.name + " is a " + doc.category_code + " company.");
        },
        function (err) {
            assert.equal(err, null);
            return db.close();
        }
    );
});

Blockquote

заметил, что курсор возвращено find() назначена var cursor. При таком подходе вместо того, чтобы получать все данные в memort и потреблять данные сразу, мы передаем данные в наше приложение. find() можно сразу создать курсор, потому что он фактически не делает запрос в базу данных, пока мы не попытаемся использовать некоторые из документов, которые он предоставит. Смысл cursor описать наш запрос. 2-й параметр cursor.forEach показывает, что делать, когда драйвер исчерпан или возникает ошибка.

в первоначальной версии вышеуказанного кода это было toArray() который заставил вызов базы данных. Это означало, что нам нужно все документы и хотел, чтобы они были в array.

и MongoDB возвращает данные в пакетном формате. На рисунке ниже показаны запросы от курсоров (из приложения) к MongoDB

MongoDB cursor requests

forEach лучше, чем toArray потому что мы можем обрабатывать документы когда они входят пока не дойдем до конца. Сравните его с toArray - где мы будем ждать все документы для извлечения и весь массив. Это означает, что мы не получаем никаких преимуществ от того, что драйвер и система баз данных работают вместе, чтобы пакетные результаты для вашего приложения. Пакетирование предназначено для обеспечения эффективности с точки зрения накладных расходов памяти и времени выполнения. воспользуйтесь этим, если можете в своем приложении.