Как стать автором
Обновить

Комментарии 14

Пару советов:
*Убедитесь, что journaling точно нигде не выставлен. Посмотрите в логах mongod (можно выставить verbosity level в 2)
* Если journaling включен, то вот это может очень сильно тормозить весь процесс docs.mongodb.org/manual/reference/program/mongod/#cmdoption--journalCommitInterval
* Как вариант — может быть еще и баг в драйвере, что bulk операция не верно реализована. В C Driver, например была такая проблема.
* Можно сравнить производительность с mongoimport чтобы посмотреть чего стоит ожидать.
Нет, journaling, естественно, был выключен и баг почти наверняка не в драйвере, он вполне стандартно слал запросы, просто в случае Acknowledged он шлет 1 пакет из 500-1000 операций, ждет подтверждение записи, второй пакет и так 2-4 тысячи раз. В случае, Unacknowledged и getLastError он выполняется все запросы ассинхронно просто ставя из в очередь, а потом ждет последний из них, используя getLastError. Попробуйте, сделать у себя эксперимент с замером производительности может быть у вас будут другие результаты и я действительно где-то просто ошибся, ничего исключать нельзя (либо в новой версии монги это уже исправлено).
Понятно. 1000 — это стандартное ограничение во всех драйверах, в смысле они его читают теперь из показаний сервера. Меньше может быть если в результате весь bson получается больше BSON MaxSize (который 16 мегабайт на данный момент).

Вообще это интересный момент, честно говоря опять же как баг в реализации. Я попробую протестировать на c driver и отпишусь.
Можете попробовать вот этот test для c driver gist.github.com/outcoldman/48369bff9347fb61a739
В connection string можете поменять w=0 на w=1, в общем мои результаты w=0 занимает около 17 секунд, w=1 занимает около 10 секунд. Должно быть, вроде, наоборот, с учетом ваших наблюдений.
Можете попробовать сами поиграться, скачайте c driver github.com/mongodb/mongo-c-driver, замените ./examples/example-client.c на мой пример, сделайте билд github.com/mongodb/mongo-c-driver#building-from-git (можно просто make, не нужно make install) и попробуйте запустить ./example-client после того как запустите монгу на стандартном порту.
Вообще-то, про размер bulk пакета однозначно написано в документации —

"""
Each group of operations can have at most 1000 operations. If a group exceeds this limit, MongoDB will divide the group into smaller groups of 1000 or less. For example, if the bulk operations list consists of 2000 insert operations, MongoDB creates 2 groups, each with 1000 operations.
"""

Не пробовали вместо getLastError просто ставить acknowledge на последний bulk-пакет?
Насколько я понимаю ваш getLastError именно так и срабатывает.
Вообще-то, про размер bulk пакета однозначно написано в документации

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

Не пробовали вместо getLastError просто ставить acknowledge на последний bulk-пакет?

Нет, не пробовал, не уверен что монга не может в таком случае поменять приоритеты обработки пакетов и обработать пакет с acknowledge перед пакетами с unacknowledged. В принципе, её в этом ничто не ограничивает, так время обработки unacknowledged не гарантируется, а вполне логично для ускорения производительности обработать пакет, требующий ответа, раньше, чем unacknowledged пакеты. А при getLastError монга должна гарантировано ждать записи всех пакетов.
«при getLastError монга должна гарантировано ждать записи всех пакетов» — а это где-то написано для случая unacknowledged bulk? Как-то это мало вероятно, особенно если там пакеты кто-то реордерит внутри. Просто юзкейс не очень понятен.

Вот что они внесли getLastError внутрь вызова — это вполне понятно и обосновано, как наиболее используемая практика.
а это где-то написано для случая unacknowledged bulk?

Да, в описании getLastError в спеке: «Returns the error status of the preceding write operation on the current connection.In previous versions, clients typically used the getLastError in combination with a write operation to verify that the write succeeded.». Не могу найти, но раньше в спеке был прямо пример такого использования getLastError, там ещё специально указывалось что все запросы должны идти по одному логическому каналу, что гарантировало что getLastError всегда дождется завершения всех записей.

Просто юзкейс не очень понятен.

Хорошо, юзкейс:
1. При acknowledge, происходит ожидание ответа о записи каждого пакета, что очень уменьшает производительность при большом кол-ве пакетов,
2. При unacknowledged невозможно понять когда можно начинать безопасно читать записанное,
3. При unacknowledged + getLastError можно понять когда можно начинать безопасно читать записанное и работает относительно быстро,
Из этого описания ничего не следует про неподтвержденную пакетную запись, lastError просто статус последней операции по данному коннекшену.

Cейчас они просто унесли эту функциональность внутрь вызова write, так как пользователей задолбало каждый раз самим звать getLastError —
«A new protocol for write operations integrates write concerns with the write operations, eliminating the need for a separate getLastError».
Тем не менее, практика показывает что getLastError именно ждет окончания всех пакетных записей, так как чтобы вернуть статус последней операции, нужно дождаться её окончания. Раньше lastError именно использовался как ручной аналог acknowledge.

пользователей задолбало каждый раз самим звать getLastError

Конечно, если реально они в последних версиях пофиксили чтобы getLastError и acknowledge работали одинаково для большого кол-ва пакетом, использовать стоит штатные методы, без всякого сомнения. Но если грубо говоря, старым методом удастся достигнуть ускорения загрузки в несколько раз, то тут уже вопрос, что лучше при данном юзкейсе новый и удобный метод или неудобный и старый, но более быстрый.
Вообще-то, про размер bulk пакета однозначно написано в документации

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

Не пробовали вместо getLastError просто ставить acknowledge на последний bulk-пакет?

Нет, не пробовал, не уверен что монга не может в таком случае поменять приоритеты обработки пакетов и обработать пакет с acknowledge перед пакетами с unacknowledged. В принципе, её в этом ничто не ограничивает, так время обработки unacknowledged не гарантируется, а вполне логично для ускорения производительности обработать пакет, требующий ответа, раньше, чем unacknowledged пакеты. А при getLastError монга должна гарантировано ждать записи всех пакетов.
Ну не знаю, в Cassandra пишется 200000 записей за 6 минут включая некоторую обработку и с гарантией записи.
Да, но требовалось-то записать 200 тыс. не более чем за 2 минуты, плюс база монги стояла на удаленном сервере, там многое «съедала» передача по сети.
ОК.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации