yurikhan: (Default)
[personal profile] yurikhan

Вынесено из комментов к посту [personal profile] vitus_wagner’а про pump.io.

Из опыта работы с MongoDB получается, что её писали вредители. Абсолютно весь API и дизайн заточен под то, чтобы как можно сильнее оградить клиентский код от возможности делать полезные запросы к базе и увеличить вероятность непреднамеренного уничтожения данных.

Типичный симптом при использовании Mongo — приложение работает, пока объём или количество документов в базе не превышает некоторого эпсилона, достаточно большого, чтобы проблемы не возникали в тестировании.

Во-первых, Mongo — блокировочник. То есть, когда в базу идёт активная запись, все читатели сидят и ждут, пока писатель соизволит отпустить блокировку.

Во-вторых, Mongo очень неохотно освобождает дисковое пространство. То есть логически удаляемые записи физически продолжают занимать место, до ближайшей компактизации. Компактизация требует, чтобы на файловой системе было свободно хотя бы ещё столько же места, сколько база уже занимает. То есть, компактизация базы, уже сожравшей всё свободное место, штатными средствами невозможна — туши сервер, снимай бэкап по сети, дропай файлы базы, перезаливай с бэкапа.

Иногда делу можно помочь ограниченными (capped) коллекциями. Это такая коллекция, которая растёт только до определённого предела. Ограничение устанавливается на общий размер данных в коллекции. Не на количество документов, не на возраст самого старого документа — на размер. Чисто техническая реализация, без какой-либо оглядки на предметную область. Далее, реализованы они так, что документы можно модифицировать, но только в сторону уменьшения размера. Удалять документы из capped коллекций нельзя, только дождаться, пока они будут удалены автоматически (при вставке очередного документа). Или можно очистить всю коллекцию. Короче говоря, capped коллекции очень ограничены в функциональности по сравнению с обычными.

В-третьих, документы Mongo ограничены в объёме неким искусственным лимитом в 16 мегабайт. Это бы было ничего для конечных документов, хранимых в базе.

Однако, иногда с базы хочется посчитать какую-нибудь развесистую агрегацию — то, что в SQL делается однострочником вида group by или right join. Для этого есть встроенные агрегирующие функции. Которые как бы работают, но их результат является документом. Со всеми вытекающими последствиями, см. п. 3.

Поэтому для всех интересных агрегаций приходится использовать механизм map/reduce. Для того, чтобы начать мочь переформулировать запросы вида group by и right join, нужно вывернуть мозг в чисто-функциональную парадигму. Писать в базу из map/reduce нельзя, там разрешены только чистые функции. Нет, есть одна лазейка: функциям, используемым в map/reduce, разрешается использовать объект контекста (так называемый scope). Объект scope является документом. Все промежуточные результаты map и reduce являются документами. См. п. 3. Если потребовать результат map/reduce напрямую (как возвращаемое значение), то он тоже должен укладываться в лимит.

Но можно делать map/reduce в коллекцию, в этом случае ограничение на весь результат снимается. Ограничения на все промежуточные документы остаются.

Часть ограничений на промежуточные результаты удаётся обойти, если делать map/reduce не по всем данным, а частями, или регулярно с переиспользованием уже насчитанных данных. Это называется инкрементальным map/reduce’ом. По умолчанию инкрементальный map/reduce перетирает прошлые насчитанные данные новыми, а не объединяет. (Это к заявлению о непреднамеренной потере данных.)

В-четвёртых, запросы на обновление (модификацию) документов. У них есть один аргумент — критерий поиска, и другой — как модифицируем. И третий — флаги/опции. По умолчанию, Mongo найдёт один документ, удовлетворяющий критерию, заранее неизвестно какой. Это gotcha, намеренное[citation needed] отличие от семантики SQL. Чтобы модифицировать все соответствующие документы, нужно явно указать флаг. Далее, если параметр, указывающий изменения, не содержит специальных операторов, то целевой (обновляемый) документ просто будет перезаписан этим. (В отличие от SQL, где указанные в запросе поля будут обновлены, а остальные — оставлены без изменения.) Это всё тоже очень помогает непреднамеренно привести базу в неизвестное состояние, из которого в общем случае нельзя ни вернуться в исходное, ни получить желаемое. Транзакции с возможностью rollback’а? Не, не слышал.

В-пятых, Mongo нестойка к аварийному выключению. При внезапном прекращении процесса файлы базы могут остаться в неконсистентном состоянии, в котором сервис отказывается запускаться и требует ручного вмешательства. Совсем как MySQL/MyISAM. Нет, транзакционная/журналируемая файловая система не поможет.

И в-шестых, Mongo очень быстро принимает записываемые в неё документы (и этот факт способствует тому, чтобы её выбирали в качестве хранилища в новых проектах), но очень неохотно отдаёт их обратно. Бэкап данных из Mongo или полная выборка для целей обработки внешними средствами подчиняется всем законам блокировочников.

Date: 2014-01-08 05:22 (UTC)
From: [identity profile] bruzh.livejournal.com
>Типичный симптом при использовании Mongo — приложение работает, пока объём или количество документов в базе не превышает некоторого эпсилона, достаточно большого, чтобы проблемы не возникали в тестировании.

этот эпсилон примерно равен количеству индексов + горячих данных и он же примерно равен объему ОЗУ. Как только начинается активная работа с дисками, все хужеет на глазах.
В принципе, MySQL работает так же. Но если при дальнейшем повышении нагрузки MySQL кряхтит, но тянет (время выполнения запросов растет почти линейно - по моим ощущениям), то MongoDB просто умирает - у нее забивается очередь выполнения, а текущие запросы как будто блокируют друг друга. Иногда вообще возникают забавные ситуации - диски временно протормозили из-за фоновых процессов, MongoDB встала колом и стоит. Убили все запросы в очереди - "отряхнулась и дальше пошла", как ни в чем не бывало.

Проблема в том, что объем индексов можно оценить, а объем горячих данных - нет.

Из-за приоритета записи возникает еще одна особенность: пока все хорошо (индексы и горячие данные лежат в памяти) - MongoDB, фактически, только пишет на диск. Но как только производительности дисков перестает хватать, MongoDB опять встает колом.

Я тоже вздрагиваю при слове "Mongo". ^_^

Date: 2014-01-08 07:46 (UTC)
stiv_sigmal: (Время не ждёт)
From: [personal profile] stiv_sigmal
Понятно, спасибо.

Date: 2014-01-08 08:35 (UTC)
From: [identity profile] qkowlew.livejournal.com
Спасибо.
Как админ хостингового сервера , буду вручать Ваш текст клиентам в контексте вопроса, "почему бы нам не использовать Mongo вместо MySQL?"

Очень выразительно.

Date: 2014-01-08 10:10 (UTC)
From: [identity profile] qkowlew.livejournal.com
Поверьте, у меня на его тему очень давно нет иллюзий. :)

У клиентов бывает иллюзия (особенно подкреплённая фанатиками-разработчиками), что смена платформы решит какую-то из его проблем И НЕ ПРИНЕСЕТ НОВЫХ. :)

Date: 2014-01-08 17:15 (UTC)
From: [identity profile] mrbiggfoot.livejournal.com
кажется одного п.5 достаточно, чтобы не использовать БД в продакшене.

Date: 2014-01-09 04:02 (UTC)
From: [identity profile] mrbiggfoot.livejournal.com
к сожалению, компы выходят из строя не только по причине обрыва питания

Date: 2014-06-15 17:59 (UTC)
From: [identity profile] honeyman.livejournal.com
> Для этого есть встроенные агрегирующие функции. Которые как бы работают, но их результат является документом. Со всеми вытекающими последствиями, см. п. 3.

Начиная с 2.6 – курсором.

No title

Date: 2014-06-15 11:38 (UTC)
From: [identity profile] livejournal.livejournal.com
User [livejournal.com profile] slach referenced to your post from No title (http://slach.livejournal.com/360234.html) saying: [...] отличный пост на тему того, что не так с MongoDB http://yurikhan.livejournal.com/59037.html [...]

Date: 2014-06-15 12:06 (UTC)
From: [identity profile] denisioru.livejournal.com
> В-пятых, Mongo нестойка к аварийному выключению. При внезапном прекращении процесса файлы базы могут остаться в неконсистентном состоянии, в котором сервис отказывается запускаться и требует ручного вмешательства. Совсем как MySQL/MyISAM. Нет, транзакционная/журналируемая файловая система не поможет.

остальное можно не читать.

Date: 2014-06-15 12:07 (UTC)
From: [identity profile] denisioru.livejournal.com
Вот в этом и дело. Окружение не всегда подконтрольно владельцу инстанса Mongo. Так что вычеркиваем вообще.

За что мы не любим MongoDB

Date: 2014-06-15 12:18 (UTC)
From: [identity profile] livejournal.livejournal.com
User [livejournal.com profile] xupypr referenced to your post from За что мы не любим MongoDB (http://xupypr.livejournal.com/469998.html) saying: [...] Оригинал взят у в За что мы не любим MongoDB [...]

Date: 2014-06-15 15:41 (UTC)
From: [identity profile] erthad.livejournal.com
Как-то неясно насчет пунктов 2 и 5:

У MongoDB разве есть компактизация? Я считал, что он измененные данные просто меняет по месту на диске.

Со включенным журналированием он вроде как должен быть устойчив к внезапным выключениям питания. Это не так? Без журналирования согласен, взрывается.

Это не наезд, а просто хочу прояснить для себя ситуацию.

Date: 2014-06-15 16:23 (UTC)
From: [identity profile] erthad.livejournal.com
Спасибо, о компактизации не знал. Может быть просто запускать ее периодически, скажем, раз в неделю?

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

Кстати, дополню ваш список: у MongoDB довольно криво и геморно реализован шардинг.
Чтобы размазать данные на 4 шарда, обеспечив при этом фактор репликации 3, нам потребуется 12 серверов, которые придется собирать в двухуровневое дерево вручную.

Date: 2014-06-15 16:24 (UTC)
From: [identity profile] bruzh.livejournal.com
>Журналирование появилось относительно недавно и, вероятно, в каких-то из тех опытов, от которых у меня остались впечатления, его просто не было или оно было по умолчанию отключено.

У этого журналирования не работает автоочистка журнала. ^_^
В доке написано, что после начала нового файла, старый должен на автомате стираться. На версии 2.4.7 это не так - тупо файлы не удаляются, приходится самим по крону стирать.

Date: 2014-06-15 16:30 (UTC)
From: [identity profile] bruzh.livejournal.com
>Со включенным журналированием он вроде как должен быть устойчив к внезапным выключениям питания.

С включенным журналированием mongodb умеет определять незавершенные операции и автоматически и сохраняет в отдельном каталоге. Теоретически, это может чему-то помочь.
На практике, роль мастера (PRIMARY) в репликасете уже полчаса как перешла на другой сервер и что делать с этими старыми запросами - непонятно. Данные могли быть перезаписаны, а как это определить? Только ручной разбор всего оплога на новом мастере, это "весело".

Date: 2014-06-15 16:38 (UTC)
From: [identity profile] symbi.livejournal.com
Значительная часть этих проблем решена в tokumx, который, по сути, заменяет весь блокирующий движок на свой версионник. Примерно то же, что innodb для mysql в свое время.

Date: 2014-06-15 18:36 (UTC)
From: (Anonymous)
Расскажите, пожалуйста, по подробнее)) мне очень интересно что и как

Date: 2014-06-15 19:25 (UTC)
From: [identity profile] alexshubert.livejournal.com
А что лучше-то?

Date: 2014-06-16 01:13 (UTC)
From: [identity profile] bruzh.livejournal.com
Лучше то, что Вам подходит.

У каждого же свои критерии "лучшести", они еще и меняются со временем.

Date: 2014-06-16 01:13 (UTC)
From: [identity profile] bruzh.livejournal.com
спасибо, почитаю.

Date: 2014-06-20 19:56 (UTC)
From: (Anonymous)
У автора sql головного мозга.
* монга нормально работает на десятках терабайт.
* проблема не в блокировках, а в i/o, так же блокировки есть и в mysql, просто о них не говорят. главное что монга производительнее.

> штатными средствами невозможна — туши сервер, снимай бэкап по сети
за памятью нужно следить, а вообще "дефрагментация" делается легко, достаточно удалить файлы, после чего монга сама вытягивает данные из реплики и нода "включается".

> лимитом в 16 мегабайт
если вам не хватает, то у вас что-то не то с архитектурой (для больших бинарников есть gridfs)
> group by или right join
тут он не нужен, как вы будете join-нить если таблица размазана по 20 серверам? + это медленно.
это вам не sql, для каждой задачи свой инструмент, если вам в проекте нужны join-ы, то вам никто не запрещает подключить (my)sql для этой задачи.
в больших проектах обычно используется куча технологий, "facebook же не на одном mysql работает..."

> map/reduce
похоже вы не понимаете для чего он нужен

> Транзакции с возможностью rollback’а? Не, не слышал.
достаточно атомарных операций, так же можно использовать транзакционный сервер где это необходимо. транзакций нет потому что - это тормоз, особенно в шардинге, тут нужно включать мозг.
и опять же если они позарез нужны, то подключите (my)sql.

5) По стабильности рекомендуемая конфигурация mongodb ещё фору даст mysql.

6) С отдачей проблем нет, если скорости не хватает - подключите серверов.
бекапы принято снимать с репликационной копии.

Date: 2014-06-21 09:07 (UTC)
From: (Anonymous)
в бд map-reduce предназначен для распределенной обработки гигантских объемов с кучи серверов, там где "goup by и join" не взлетят, поэтому смысла их сравнивать нет.

> восстанавливая базу с бэкапа после каждой неправильной попытки
вот пример (http://cookbook.mongodb.org/patterns/perform-two-phase-commits/) коммита, как можно провести операцию с возможностью rollback, причем операции с одним "счетом" могут проводиться в одно и тоже время, когда с транзакциями будет "очередь". это не sql, тут нужны другие подходы.

И как я выше уже отметил, не надо пытаться сделать все на одной технологии, например у меня были проекты где Mongodb и mysql вместе. даже для простого сайта используется 3-10 (и более) разных технологий (веб-сервер, бд, python/php...), что страшного подключить ещё одну?. Правда для мизерных "пет-проджектов" оно не нужно, там можно и в файлах хранить.

Date: 2014-06-23 20:34 (UTC)
From: [identity profile] theambient.livejournal.com
пока читал - все руки чесались написать гневный проясняющий комментарий, но Вы меня опередили )

Date: 2014-06-23 20:48 (UTC)
From: [identity profile] theambient.livejournal.com
если я не ошибаюсь, то весь nosql, представителем которой является и монга появился отчасти из попытки маштабировать горизонтально, кластеризовать базы данных. В sql мире это аукалось потерей производительности из-за сложности операций, предлагаемых реляционной моделью (JOIN-ы и прочее) и гарантиями, предлагаемыми реляционными СУБД (транзакционость). Поправьте, если не прав.

Так что нет ничего удивительного, что монга неявно апедполагает наличие реплика-сета и отсутствие транзакционности.

Но это не опрадывает
> а вообще "дефрагментация" делается легко, достаточно удалить файлы, после чего монга сама вытягивает данные из реплики и нода "включается".

Profile

yurikhan: (Default)
Yuri Khan

August 2018

S M T W T F S
   1234
567891011
12131415161718
19202122232425
26 2728293031 

Links

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated 2026-02-06 10:46
Powered by Dreamwidth Studios