Pull to refresh

Comments 125

В другой раз мы заметили тормоза и определили, что причиной их стал кластер MongoDB. Но мы так и не смогли разобраться, что именно тормозит в базе. Независимо от того, какие средства для отладки и сбора статистики мы пробовали.

Насколько я помню у MongoDB есть поддержка, так что непонятно что помешало ей воспользоваться…
Да, они, кстати, взвинтили цены вдвое на этот год, и поддержка все также является «интерфейсом к документации» за $10 000 в год за ноду то?
мб это не они, а курс rur:usd?
К сожалению в нашем случае рубль не играет никакой роли. Стоимость Production Support по прайс листу $5400 в год за ноду, а Enterprise Advanced и того больше, около $10000.

Сравнивая с поддержкой других вендоров, где за Вас с радостью все сделают через teamviewer, если это необходимо… То поддержка mongodb, как говорится, «Sucks Balls»…
Минусы MySql какие-то невнятные, похоже они тут для красного словца вставлены, ребята видимо любят использовать то что никогда не пробовали.

PS
1) STRICT_ALL_TABLES
2) InnoDB

Минусы mysql можно долго описывать и уже не раз это делалось.
Например, для меня самые главные минусы: нежесткая типизированость и отсутствие адекватного планировщика запросов. Как следствие, например, order by по 2м индексированным полям в разы дольше чем order by по 1 полю + сортировка в коде и многое другое чем postgresql не страдает. А уж что еще умеет postgresql, того в mysql никогда и не будет, скорее всего.
Ах да, я забыл про пляски с бубном при настройке mysql =)
По факту лучше 1 раз разобраться с postgresql и получать profit чем страдать с mysql.
Ок. Не прошло и 10 лет =)
Все-равно яблоко от яблони далеко не падает =) mysql сама по себе сделана вопреки стандартам языка sql, так что научить ее чему-то реально полезному сложно.
про «нежесткую типизированость» я уже в этом топике 3й коммент пишу, ладно доки не читать, но хоть комментарий на который отвечаешь.
по поводу order by:
1) postgres тоже бывает ошибается, но вот use index в нем нет, а в mysql есть хотя костыль да
2) решение тут простое — либо комбинированный индекс или оборачиваете свой запрос с одной сортировкой в select * from () as q order by f1, f2
В общем опять какие-то детские примеры превосходства pg, где транзакционный ddl, window function, with, условные индексы, gist (и другие не btree) индексы, индексы от выражений и т.п.?

В pg например having не работает для вычисляемых полей и все также берешь и оборачиваешь в подзапрос, или например update в pg работает всегда, даже если там тоже значение (с резервирование места, записью и т.п.), а mysql такое сама оптимизирует или отсутсвие в pg адекватного партицирования (проще какой нить pg xl настроить для этих целей) а в mysql из коробки и относительно удобно, но этож не значит что pg плохой после этого и его не стоит использовать.

Всё это по сути особенности конкретной БД. А, видимо, не зная их ребята уже заклеймили монгу и mysql и возможно через пару лет заклеймят также и pg и героически переедут куда-то еще (наверно на очереди что-то для bigdata).

Да и выбрав монгу, говорить что самая большая проблема это отсутствие схемы… это как минимум странно…
Детские примеры только потому, что они чаще всего играют важную роль т.к. частенько вылезают боком.
Партиционирование для postgresql нужно немного допилить напильником чтобы оно было автоматизированным, но зато есть гибкость настройки. У mysql список ограничений больше всей остальной документации по партиционированию. Уж не знаю насколько ограничения критичны, но их многовато и их нужно все знать чтобы грабли не дали по лобешнику.
Еще полезно знать и использовать типы транзакций ибо deadlockи никому не нужны.
С having да, проблемка. Не знаю точно причины почему так, но предполагаю, что проблема с производительностью.
На своем опыте с myslq я страдал намного чаще чем с postgresql. Возможно причина в том, что учили меня использовать стандартный sql (использовали interbase), который чуть что не так — плюется ошибкой, и я по инерции ожидал такого поведения от mysql, но не тут-то было =)
Хотя я mysql до сих пор использую, но не делаю на нем ничего сложнее простых сайтов с 8-12 таблицами в БД. В таких случаях он все же лучшее решение. Хотя все-равно страхую кешированием =)
В pg например having не работает для вычисляемых полей

Работает, просто там нельзя использовать alias, который задан в списке select. Вот так, например, работает:
SELECT city, count(*) cnt FROM users GROUP BY city HAVING count(*)>1

А вот так работать не будет:
SELECT city, count(*) cnt FROM users GROUP BY city HAVING cnt>1


например update в pg работает всегда, даже если там тоже значение

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

Ну а если честно, кто не любит попользовать что-то новенькое? ;)
Ещё одна фундаментальная проблема, с которой мы столкнулись – это основная особенность MongoDB, а именно, отсутствие схемы. В некоторых случаях это даёт преимущества. Но во многих случаях это приводит к проблеме неявных схем. Они определяются не движком хранения данных, а на основании поведения приложений и прогнозов.

Очень попахивает плохим архитектурным решением с предсказуемым результатом. Боюсь тут не в монге дело.
Говоря честно, я с самого начала не понимал моду на нереляционные СУБД.

Это как выкинуть в мусорку все наработки за последние лет двадцать в этой сфере. Это же данные. Они должны быть структурированы. Они должны быть связаны. Их структура должна легко изменяться, при необходимости. Они должны проходить валидацию перед изменением.

Как вообще можно жить без всего этого?) Можно хранить в Монго какой-нибудь кэш, но делать её своей основной базой?..
А кто сказал что если монга то сразу хранить мусор? У нас вот например высокосвязанная ODM с жесткой структурой и типизацией.
image
Для данных «реального» мира она часто подходит лучше чем реляционные базы.
Что вы подразумеваете под термином «данные реального мира»? Объясните пожалуйста подробнее.

Как вы решаете проблему изменения структуры таблиц?

Как вы удаляете связанные данные из базы: за это у вас какой-то код в приложении отвечает?
Что вы подразумеваете под термином «данные реального мира»? Объясните пожалуйста подробнее.

Возможно я некорректно выразился, те данные которые желательно держать ближе к родителю. Например роли юзера (массив ролей), теги поста. Или кучу спеков продукта. Или когда адрес доставки и купленные товары «вложены» (денормализованы) в заказ. Снесете адрес — заказ останется, удалите товар — заказ останется. Но естественно необходимо учитывать актуальность вложенной информации в чувствительных местах.

Как вы решаете проблему изменения структуры таблиц?

Здесь нет структуры таблиц, есть структура моделей которые мапают данные. Если надо изменить — беру и изменяю модель, или расширяю существующую модель с новыми полями (по сути полиформизм на уровне базы).

Как вы удаляете связанные данные из базы: за это у вас какой-то код в приложении отвечает?

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

P.S. Лично я использую гибридные базы (Mongo + SQL).
Например роли юзера (массив ролей), теги поста

Массивы поддерживает postgres. Для таких целей этот тип и создавался. И давайте возьмем не пост, а допустим баг-трекер. Нам нужно иметь возможность изменить цвет, или название тега, как вы это сделаете в монге? Пройдетесь по всем постам и замените?
Для всяческих нечетких структур появился JSON и JSONB (который по крайней мере до 3.0 был быстрее и компактнее).
PS я пробовал монгу, на мой взгляд она отлично подходит для прототипов, когда еще не ясна четкая структура, а валидация перед вставкой и так и так нужна.
Вот знал что Postgres поднимут, специально сделал ODM совместимым с ним. :)
Нам нужно иметь возможность изменить цвет, или название тега, как вы это сделаете в монге?

Элементарно, я не буду использовать Монгу.
Замечательно. А если это требование пришло после года разработки проекта?
В чем проблема промигрировать эту часть в реляционную базу оставляя связь по MongoID? Хотя я и так бы не стал хранить теги в полном виде, массива ID будет достаточно.
А почему бы не хранить теги не в виде массива строка, а в ввиде массива объектов? Вот например так это описывается в модели Mongoose:

var postSchema = new Schema({
  ...
  tags: [new Schema({
    id: {type: Schema.Types.ObjectId, ref: 'Tags'},
    name: String
  })]
  ...
});


Тогда при вставке поста будет проверяться наличие тега в коллекции Tags и если он присутствует, то в id будет подтягиваться ObjectId из коллекции Tags и если нужно будет изменить имя тега, то в коллекции Tags должен быть хук, который после обновления поля name обновляет в других коллекциях это же поле.
Именно так они и хранятся у меня, просто тут шло обсуждение гипотетической ошибки сделанной в гипотетическом проекте.
У вас же реляционная схема полностью. Зачем вам mongo?
Ага, особенно там где Updates и Assignments. Я монгу использую не потому что она монга, а потому что можно делать гибкие схемы и расширять функционал послойно не трогая базу, вы предложили задачу — я показал пример.
Они должны быть связаны.
Да, но част вырожденный случай — одна «таблица», ни с чем не связанная.

Их структура должна легко изменяться, при необходимости.
Не всегда. Особенно если поддержка этой «легкости изменения» влетает в копеечку при каждом, любом запросе.

А вообще, все что вы написали — это не свойство «нереляционных СУБД», а молодых (просто не успели напилить фич) или «быстрых» СУБД, которые жертвуют многим ради скорости. Они бывают как реляционными, так и нереляционными.

Выяснилось, что реляционная модель, 1) далеко не всегда удобна 2) ее очень сложно (или невозможно) реализовать реально быстро. Поэтому на волне моды на скорость, мало кто берет реляционную модель. Однако, это не аксиома. Так же, как и не аксиома, что нереляционная БД — обязательно «нетипизированная», «невалидируемая», и т. д.

Короче говоря, не путайте модель данных со свойствами базы.
Во-первых, никто никуда ничего не выкидывал. Просто не надо использовать «не то не для того».
Во-вторых, schemaless решениям уже много лет, и монга тут не принесла ничего особо нового.

Не понимаете? Ну вот пример — платформа IBM Lotus/Domino, на которой крутится документооборот и почта очень-очень больших и серьезных контор. В RU в основном можно встретить в банках и гос-структурах.
Под капотом — документоориентированное хранилище Notes Storage. Схемы нет, концептуально довольно близко к монге.

А вот вам юзкейз. Тот же документооборот в крупной старой организации. 40 филиалов по всему миру, почти во всех часовых поясах. База реплицируется в каждый филиал.
В середине дня приходит установка — в такой-то форме нужно добавить новое поле — «Номер телефона». Сегодня. В уже существующих 50млн документах его нет, и юзер должен увидеть на форме значение — «Не заполнено». В некоторых документах оно будет заполняться, а в некоторых — так никогда и не появится. Конечно, базу(ы) нельзя блокировать ни на секунду. Еще ты помнишь, что филиал в Мухосранске реплицирует эту 50гиговую БД раз в сутки в 5 утра по DSL каналу 128кбит/с.

Так вот, эта задача на Lotus/Notes решается за 15 минут с тестированием и наливанием чая. Филиал в Мухосранске в 5 утра получит дополнительно лишь копеечное обновление бизнес-логики приложения, даже ничего не заметит. Все обновления прозрачно расползуться по всем филиалам при первой же репликации, при этом не будет никаких нестыковок «схемы».
Если у вас не было таких задач, я вам даже завидую. У вас впереди много открытий чУдных. ;)
Да, работ подобных объёмов у меня еще не было) Спасибо за комментарий, вы изменили в определённой мере моё мнение о подобных СУБД.

Но у меня сразу возникает вопрос: получается, что мы код пишем, который должен потенциально работать с объектами, которые могут иметь несколько разных версий структуры своих данных? Не превратится ли подобный подход к разработке приложения в мучение через какое-то время? Об этом и написано в статье, которую мы тут обсуждаем: необходимость следить за тем, какие данные и в какой структуре лежат в каждой конкретной записи.
Нет, просто любые изменения необходимо фиксировать в соответствующих документах.
И это касается абсолютного большинства сложных систем.
Рад за вас.
Само-собой всё не бесплатно. Но, например, в том же Lotus-е такие ситуации очень помогает разрулить сама платформа. Хорошо бы иметь опыт с ней, но попробую объяснить, упрощенно. Просмотр и изменение документов юзером там реализовано через «формы» — грубо говоря это шаблон из набора полей + возможно логика обработки (кнопки).
Например, форма с полями — «Имя», «Фамилия», «Отчество». И кнопка «Save», которая просто сохранит изменения.
С помощью любой формы можно открыть любой документ — на просмотр или редактирование (решается ACL).
И тут самая тонкость: при открытии документа, на нашей форме будут заполнены те поля, которые существуют в документе. Пример: в документе заполнены все три поля — тогда в открытой форме все 3 поля будут заполнены значениями из полей открытого документа.
Пример2: в документе не заполнено поле «отчестство». При его открытии на форме это поле просто останется пустым. Это по дефолту. Можно, если нужно, добавить форме «ума», чтобы если поле не заполнено, то отображать в нем что-либо, типа «ЗАПОЛНИ МЕНЯ». Или выдавать messagebox, или что угодно, что нужно. Но, повторю, это не обязательно, по умолчанию оно просто останется визуально пустым.
При этом, если юзер таки заполнит поле «отчество», нажмет «Сохранить», то соответствующий документ обновится — в нем появится новое поле с заполненным значением.
Пример3: в документе вообще нет полей Ф, И, О, зато есть поле «Телефон». При открытии через нашу форму все поля будут визуально пустые. Мы можем заполнить, например, «Имя», сохранить. В документ ДОБАВИТЬСЯ новое поле «Имя», а все остальные поля останутся как были.

Вот примерно так. На самом деле я уже давно не работал с Lotus, но только спустя годы, вспоминая тонкости этой платформы, работая с другими системами, я понимаю насколько круто там всё было спроектировано. Не идеально, косяков хватало, конечно. Но для систем такой сложности их крайне мало, imho.

Примерно так-же работает Сервис Менеджер BMC Remedy, вот только он в качестве базы использует различные реляционные СУБД(DB2, Oracle, MS SQL, etc.), что несколько замедляет его работу.
Большое спасибо, теперь у меня многое расставилось по местам)

Да, если работать с нереляционной СУБД с таким подходом, получается вполне себе неплохой вариант. Мне нравится.
Единственное «но» для всего этого — это необходимость писать код своего приложения соответствующим образом, когда в реляционной СУБД вся ответственность на сохранение структуры перекладывается на базу, что на определённую долю облегчает программистам работу.

Ну и согласитесь, не всегда у нас возникают такие страшные ситуации, как реплицирование 50-гиговых БД по DSL-каналу в 128кбит/с. И это уже больше задача сисадминов, ответственных за прокладку нормального канала связи между хранилищами данных системы, а не проблема СУБД.
И это уже больше задача сисадминов, ответственных за прокладку нормального канала связи между хранилищами данных системы, а не проблема СУБД.
Нечего сваливать на сисадминов невыполнимые задачи. Что, если в городе всего один интернет-провайдер?
Таким образом мы пришли к выводу, что нереляционные СУБД полезны для хранения огромного количества данных, распределённых по российским глубинкам с едва работающей связью… Этот факт, кстати, надо ещё поверить: действительно ли Монго сможет в таких условиях реплицироваться лучше какой-нибудь Postgres…

В общем, ок: если когда-нибудь возникнет такая ситуация, я подумаю о Монге или чём-то подобном)
Нет, почему вы делаете общий вывод о всей концепции лишь по одному частному use-case для одной из реализаций? Исходно вы написали, что не представляете где вообще могут реально пригодиться такие хранилища — я лишь привел один из примеров.
А вы уже зачем-то притянули сюда глубинки (не обобщайте на только российские, кстати тоже) и тп. Варианты использования таких хранилищ существуют, существуют давно и успешно, что подтверждает Lotus. Просто это бесконечная тема — «я забиваю гвозди микроскопом, и он раскалывается на 10-ом гвозде, значит микроскопы — _овно!».

Про тонкости репликации postgres'a не скажу. В лотусе репликация суперская, там всё круто. В монге репликация выполняется передачей реплике всех модифицирующих команд (oplog), выполненных на другой. Мы немного используем репликацию монги, если честно, местами выглядит слабовато и мутно. Например, если PRIMARY реплика убежала далеко вперед, т.е в oplog уже потерлись команды, которые должны были быть переданы другой реплике, то реплику придется восстанавливать «с нуля». Короче, нужно либо закладывать размер oplog'a таким, чтобы туда вместились все изменения на максимальный период простоя других реплик, либо следить, чтобы реплики не «лежали» дольше, чем может вместить в себя oplog…
Спасибо вам за ваши разъяснения и рассказы из личного опыта)
Обычно это проблема не админов, а менеджмента — админы предлагают решение типа «запускаем на каждый филиал геостационарный спутник и репликация летает во всех смыслах слова», но менеджмент не соглашается с оптимальным техническим решением «почему-то», требуя не техническое, а технико-экономическое обоснование нескольких вариантов и тогда внезапно оказывается, что годы работы программистов дешевле чисто аппаратных решений, которые предлагают админы.
А как там работает поиск документа?
Т.е. если мне, например, надо выбрать пользователей с телефонами заканчивающимися на «0»?
Там есть полнотекстовый поиск, «изкоробки», с поддержкой простеньких wildcard и fuzzy-search. Но можно написать свою реализацию поиска, на Java или LotusScript.
Это очень кратко, повторюсь, я несколько лет плотно не работал с платформой. Скорее всего есть реализации каких-то поисковых движков. Судя по отзвукам, последние версии платформы привнесли много нового, не читал подробно.
Вообще, платформа Lotus это такой авианосец enterprise уровня, работающий уже второй десяток лет. Это к тому, что нет смысла искать в нем ахилесову пяту — даже если она есть, то всё равно лучше пока никто не сделал.
Это очень-очень частный случай, когда отсутствие схемы действительно выгоднее, но возвращаясь к контексту MongoDB — большинство идеологов монги проповедуют отсутствие схемы несколько в ином ключе — в духе что мол код писать быстрое, не надо проектировать схему — самое то для стартапов. Поставил базу и побежали.
Собственно в статье основная претензия к монге в плане отсутствия схемы — что приходится логику приложения усложнять. И это действительно так. Без схемы и правда получается быстрее на каких-то ранних этапах развития некоторого абстрактного проекта в вакууме. Но в последствии это преимущество сводится на нет фиксом всяких нетривиальных багов. Да и самый частый кейс — программист уволился/заболел/ушел в астрал, и пади там разбери без схемы, что происходит в базе на 20 млн. документов. Конечно идеологи монги могут сказать — «смотри в код», но тут надо понимать что чтобы понять что происходит в базе нужно смотреть не только текущий код но и все ревизии кода с самого начала, потому что хрен его знает как там база менялась на протяжении жизни проекта.
Конечно можно использовать всякие mongoid или там mongoengine (в python), но зачем? Если в этом действительно появилась потребность, то лучше чтобы за целостность схемы отвечала БД, а не приложение. Так что на мой взгляд претензии к shemaless, описанные в статье, вполне себе обоснованные.
Но кейс, описанный вами, оправданный.
На самом деле автор написал странную вещь: «Мы изменили название поля title в базе и после этого код поломался»
А с реляционными БД иначе дело обстоит? Там пришлось бы и схему менять и код.
А я могу всё перевернуть наоборот! =)
Мощь RDBMS базируется на реляционном исчислении. Это чистая математика, вылизанная и доказанная. Можно точно сказать, что имея данные в нормализованном виде, с помощью реляционных запросов можно получить выборку любого вида по ним — группировки, join'ы, и тп.
И как раз в ЭТОМ случае вы можете ничего не знать про «схему»! Пишите юзеров в таблицу «users», пишите их комменты в таблицу Comments, связывайте их по id. И т.д. А дальше — какие бы требования к приложению вам не выдвигали, с помощью SQL и нормализованных данных вы получите любую нужную выборку. Заплатив в том числе и скоростью.

В случае с nosql мне бы лучше заранее знать — какие данные должны быть «рядом», т.е денормализованы, а какие можно раскидать по коллекциям, связав по какому-то полю, например. Ошибка на этом этапе может потом заставить обновлять большое количество документов, дописывая в них какое-то недостающее поле, например.

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

Да. И никто не отменял использования и того и другого одновременно. :)
К сожалению, чистая математика есть только на бумаге — в статьях Кодда, в классической книге Коннолли-Бегга-Страчана и т.д. А в реальной жизни в каждой РСУБД есть какие-то особенности, которые нельзя забывать.
Скажите, а что вообще заставляет вас засовывать строки в int поля?.. Я чето не понял фишки.
Никто не заставляет, но warning при попытке такой встаки это хорошее средство отлова неявных ошибок

Другой пример, вы хотите сохранить в MySQL поле facebook_id и указываете поле INT 11 (по незнанию, что есть длинные ID). При попытке вставки ID больше max int оно просто запишется как 2147483647… по тихому, без ошибок.
Т.е по сути парни сменили движок и потратили ресурсы на его изучение только потому, что не прочитали документацию)
Вот уж не думаю что после миграции на mysql из mongo они бы получили прирост к производительности =)
Зато они получили такой набор функционала от postgresql, что они вполне могут довольно сильно поднять производительность.
Они получили безценный опыт же!

Обновили резюме, попросили повышение…
Это так удобно, когда надо явным образом выставлять все окружение, что бы твои запросы работали одинаково.
Особенно когда это окружение нельзя изменить SQL запросом, а необходимо править конфиг сервера.
По уровню PITA MySQL наверно лидер, о чем собственно и статья.
Если у вас только одно приложение работает с базой данных, это не страшно. А если их дюжина, то всё это быстро превращается в кавардак.
Это одна из архитектурных ошибок и база тут не причем, видимо поэтому у них и появлялась проблема:
К примеру, задав поле как int(11), вы можете вставить туда текст
По хорошему одно приложение (одна логика, много инстансов) должна работать со «своими» данными и предоставлять апи всем остальным.
К примеру, задав поле как int(11), вы можете вставить туда текст
По хорошему одно приложение (одна логика, много инстансов) должна работать со «своими» данными и предоставлять апи всем остальным.

Оно так и будет, но только когда вы обнаружите эту ошибку =) Мое мнение такое — если пришла непонятная или неожидаемая фигня, то приложение должно упасть, известив вас о произошедшем. Тогда тупые ошибки по недосмотру вылавливаются моментально, а не после часа поисков. И вот тут жесткая типизация postgresql приходит вам на помощь
Оно так и будет, но только когда вы обнаружите эту ошибку. И вот тут жесткая типизация postgresql приходит вам на помощь
Я про то что если «Вася» написал скрипт (свое приложение) который в вашу «1С SQL» начинает делать insert-ы, то жесткая типизация не спасет от кривых данных. Должно быть единое апи через которое все работают.

Часто это не то, что не реально, но требует очень больших затрат на пару-сервере. Грубо говоря, выполнить джойн по миллиону записей лучше средствами субд, чем получать по миллиону с двух при и джойнить их в приложении.
UFO just landed and posted this here
Umputun и Bobuk хвалили монгу в Радио-Т, если вы их не знаете то вы в программировании всего года 2-3 :)

При работе с разными sql схема данных обычно в базе (реально это не всегда так, часть схемы вполне может оказаться в приложении и/или триггерах), при работе с nosql — обычно в приложении. Она всегда есть, явно или неявно.

В текущей ситуации злую шутку сыграл низкий порог вхождения для начала работы с mongo. По большей части, люди не понимают, что схема данных и её эволюция всё равно где-то будет описана. И та же mongo прощает куда больше, чем cassandra, hbase или riak, например.

Особенно смешно, когда люди начинают пихать в mongo данные, которые отлично раскладывались в sql. Или мучаются с отсутствием ACID-гарантий, самостоятельно ступив на этот путь боли и страданий)

Хотя аналогичные вещи можно увидеть и в sql-мире, когда люди начинают складывать в базу тяжелые блобы, которые могли бы прекрасно жить на fs.
Какой болезненный пример вы привели. Я складываю тяжелые блобы в InnoDB в старом проекте :(…
(эта часть проекта переписыватся на Mongo, но на шее висит поддержка старого)
Рад за вас, а мы какраз затеяли переход в обратную сторону(правда не монго скорей всего а касандра). Логика запросов со временем выросла в монстра которому чтоб срендерить одну страничку надо половину базы перекопать.
Проблема усугубляется еще тем что не возможна репликация/шардинг нормальные(половина логики в скриптах БД со смешанной записью/чтением).
Ну и наконец данные не совсем подходящи, изначально попытались совместить несовместимые сущности в одной табличке и в итоге нарвались на гору неочевидных связей, рекурсий и прочего тяжелого кода.
Заглянул в ваш профиль, посмотреть, не вместе ли мы работаем. Ситуация один в один.
Опять 25.
— MongoDB не для тех данных, которым нужна связность (например: события системы статистики, журнал действий пользователя, развесисты настройки разных объектов, которые еще и создаются пользователями приложения и т.п.)
— MongoDB эволюционирует, но в каждой статье пишут о старых болячках с writeConcern и локом на базу/коллекцию. В вышедшей неделю назад 3.0 с движком wiredTiger уже есть и document-level лок и транзакции
— MongoDB Inc. работают и весь код открыт и многие ругают его из своих уютненьких проектов, где бы тоже порыться и посмотреть, а может там и тормозит потому что виновата не база, а то что между стулом и монитором.

" until we replaced the primaries of the cluster " — наверное имеют в виду, реплику, писать можно только на primary, когда отключается primary, происходят «выборы» и из secondary выбирается новый «primary», возможно речь об этом.

В целом дух таких статей — «не используйте mongodb, потому что она плохая», но собака лает, а караван идет, и за время десятка статей монга обрастает сообществом, хорошими драйверами (native библиотеками для разных ЯП — C, C++, PHP, Java, Scala, Ruby и т.д. и это только, те что спонсируются mongodb inc. ), новыми возможностями (например, aggregation framework, snappy сжатие, batch update), хорошей документацией, кучей ODMов и прочих улучшателей жизни.
Основная структура приложения практически всегда подразумевает связанность. Как например связь между пользователем и списком ролей вполне однозначна. При удалении роли нужно и проверить всех пользователей. Данные задачи лучше отдать на откуп реляционной базе.

А монга, как выше сказано для данных которым не нужна связанность. В идеале для данных которые бьются на отдельные документы никак не зависимые друг от друга.

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

Схема описывается в Document, аналог Entity в ORM. По сути с DoctrineORM то же самое — все равно код контроллирует (повторяет, валидирует) схему на своей стороне.
Приведу еще один довод в пользу nosql, раз уж пошла такая пьянка.
Попробуйте в InnoDB вставить 200м записей, желательно хотя бы за час. И без читерства с отключением индексов — они потом собираться будут еще час после записи.
Это довод не в пользу nosql, а против innodb.
Жду рекомендаций, какая RDBMS может втянуть в себя такое количество записей
Oracle, MS SQL.

(к сожалению, не first-hand knowledge, поэтому примеров не будет)
попробовал вставить 1м записей в pg, в достаточно большую таблицу с десятком constraints и внешних ключей и с десятком индексов, (пару gist, пару функциональных + btree)
заняло 112 секунд в виртуалке на ноуте. при этом я получаю гарантированно связанную БД и весь процесс полностью транзакционный, ну и про отключение индексов — в pg их можно «собирать» параллельно, что хорошо походит для единовременной загрузки большого кол-ва данных
А как заливали? Импортом или инсертами? Ну и вся суть состоит в том, что 1-5М записей вливаются быстро, а потом начинаются жуткие тормоза, по крайней мере на mysql.
просто сгенерировал sql файл c bulk insert (вернее он был, просто округлил до 1м строк). есть еще pgloader он может быть даже побыстрее, но лично его не тестировал
А монга втянет? Мне помнится, что там тоже чуда не происходит.
Монга втянет, пускай неидеально, но раза в 3 быстрее. Еще быстрее втянут cassanda и couchbase. Более того, горизонтальное расширение и кластеринг, например, в монге и каучбэйсе проще.
Но за час тоже 200м не втянет, верно? Я работаю и с монгой и с мускулем и не могу сказать, что монга невероятно крута в плане скорости.
Бенчмарк на коленке:

mongo.php
<?php

$client = new MongoClient;
$collection = $client->selectCollection('bench', 'bench1');
for ($i = 0; $i < $argv[1]; $i++) {
    $collection->insert(['data' => 'habrahabr']);
}



mysql.php
<?php

$db = new PDO('mysql:host=localhost;dbname=bench', 'root', '');
for ($i = 0; $i < $argv[1]; $i++) {
    $db->query('insert into bench1 (data) values ("habrahabr")');
}



root@e109a01d3001:/# time php mongo.php 1000  

real    0m0.176s
user    0m0.055s
sys     0m0.034s

root@e109a01d3001:/# time php mysql.php 1000

real    0m3.961s
user    0m0.075s
sys     0m0.046s


О боже мой! Срочно переписываем все на монгу!!!
Но успокоимся, сделаем пару глубоких вдохов и добавим concurrency:

root@e109a01d3001:/# time (for i in {1..100}; do php mongo.php 1000 & done; wait)

real    0m8.242s
user    0m7.763s
sys     0m5.352s

root@e109a01d3001:/# time (for i in {1..100}; do php mysql.php 1000 & done; wait)

real    0m8.937s
user    0m4.027s
sys     0m3.929s



И как-то профит совсем не грандиозен. It depends, впрочем, как всегда.

mysqld 5.5.41
mongod 3.0.0

Как-то так, господа несогласные.
На 1000 итераций разницы не будет, пробуй на 1М, 10М, 100М. Добавь индексы в базу.
Ну так это сферический конь в ваакуме, без индексов на продакшне делать нечего.
У вас в варианте с mysql происходит своя транзакция на каждый insert? В монго каждый insert проходит атомарную транзакционность, хотя там можно сделать bulk insert.
Вы использовали WiredTiger или mmap_v1?

Я бы добавил объема к записям, + в монго варианте пишется 2 поля (_id и data), а в mysql только 1 колонка.
Как вариант, я бы ещё попробовал бы конкурентное изменение одной строки/документа, а то в линейной записи быстрее всех будет обычный «текстовый файл».

PS: в наше время пора предоставлять docker файл к тестам, чтобы все желающие могли запустить у себя.
Мне эта дискуссия малоинтересна, поэтому развивать тему бенчмарков я не стану.

Эта ветка началась с комментария о превосходстве монги по скорости, в чем я усомнился, ссылаясь на свой практический опыт.

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

Скорость не является безусловным аргументом в пользу монги. Любые другие фичи — да, скорость — нет.
На самом деле вы там тестировали не работу монги vs mysql, а больше скорость интерпретации php скрипта + подключение к БД.
Кластеринг в монге — головная боль Ops человека, особенно в облаке, когда подразумевается наличие гибкости системы. Гемор с конфиг-нодами и портами шардов — та еще свистопляска… Структура сама по себе не user-friendly (как например у Couchbase или ElasticSearch), и из-за остуствия прозачности, скорее всего, и появляются сложности типа
until we replaced the primaries of the cluster


Вообще, достаточно много нюансов для правильной работы всей системы (особенно когда она живая, и переодически двигается туда-сюда).

Недавно менял базовый образ для каждого инстанса кластера наживую, были сложности, конечно. Но не на столько чтобы пойти и убедить всех перестать использовать MongoDB.
Это будет работать только в случае, если есть заранее сгенерированные данные, которые надо влить. Если идет поток с приложения, то этот способ не годится.
Сгодится. Правда придется приложение доработать.
У нас, например, есть 16 серверов, которые генерят данные. Делать инсерты сразу в БД мы перестали еще когда серверов было два.
В итоге сейчас данные пишутся локально на каждой машине в минутные файлы, там же локально обрабатываются если надо (cat, awk etc.) и потом льются в MySQL с помощью LOAD DATA INFILE на скорости до 10M записей в минуту.
Очень специфичный подход. Во-первых, в таком случае доступность данных немоментальная. Во-вторых, небезопасная — пока данные не попали в базу и не расползлись по репликам, можно потерять файл дампа. В-третьих, это двойная работа, причем сливание потока в файл — это доп. нагрузка на IO.
Одним словом, все это как минимум странно, хотя и не лишено права на жизнь.
Конкретно в нашем случае это самый лучший подход.
Отставание (которое составляет не больше 2-х минут) совсем не критично. Потеря данных нестрашна в силу того, что одни и те же данные как правило повторяются на нескольких серверах. А что касается нагрузки на диски, то даже для начального сервера записать файл размером 200-300 МБ в минуту и одновременно отдавать такой же файл за прошлую минуту — вообще не нагрузка с точки зрения IO (порядка 5% по iostat).
Хотя согласен, все зависит от задачи и для горячего онлайна, а тем более для транзакционных данных, такое решение не подойдет.
Мне кажется, ничего страшного в подобном переходе нет.

Многие начинают с одной базы/языка/технологии и т.д. и потом переходят на другую. Тому могут быть самые разные причины, но, как правило, общая причина та, что выбранный продукт перестает удовлетворять требованиям и структурам конкретной компании-архитектуры. Вот и все. Это абсолютно не повод ругать продукт, выбранный первым. И совершенно не повод опровергать смысл перехода на другой. Просто еще одна, очень конкретная история, из которой не надо делать глобальных выводов.
Часто бывает, что на первых этапах разработки выбирается какой-то инструмент из класса, удовлетворяющих начальным требованиям чисто по личным предпочтениям разработчиков. Не бизнес принимает решение выбора между сэкономить сейчас с десятикратным запасом прочности или сэкономить потом на переходе и сразу со стократным запасом.
Который раз уже люди ноют — без схем плохо. Правильный путь — схемы нужны, но на уровне приложения. Философия в том, что не нужно определять схему два раза, достаточно это сделать в приложении.

В случае с sql-базами, схема определятся два раза: на уровне приложения, и на уровне базы.

В случае использования чего-нибудь вида hibernate c автоматической генерацией таблиц схема тоже описывается всего лишь один раз.
Это все равно определение схемы на уровне приложения, формально.

Да есть куча миграторов: rails-овсие миграции для рубистов, south (который теперь в django orm), для java hibernate.

Но: если программист все равно не лазит в схему руками, и она отдана на откуп автогенераторам, зачем вообще нужен слой определения схемы на уровне БД? Зачем каждый раз 2 раза проверять валидность полей на каждом запросе?

Если скажете что для надежности, то если я сделал ошибку в описании схемы на уровне прилы(не поставил проверку уникальности, неправильное ограничение на поле), она автоматом замапится в БД). Эти ошибки должны ловиться авто-тестами, а не двойными идентичными проверками.
Надежность тоже повышается. В реляционных бд проблем с транзакциями меньше чем у нереляционных.
Разговор был про схемы.

А проблемы с транзакциями, из-за неправильно выбора СУБД и инертности мышления,. Люди пытаются применить подходы из SQL в noSQL.
Разговор был, что в sql базах схему надо описывать два раза и вместо того, чтобы решить эту проблему через скажем авто-генерацию вы предлагаете перейти на бд где нет схем.

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


Верно, про это. Я так и не понял, в чем плюсы двух уровней одинаковых описаний? Или слишком радикально выкидывать схемы? Все зависит опять таки от ситуации, для некоторых систем это действительно удобней. Я не говорю сейчас, что стал бы проектировать банковский процессинг или что-то подобное с mongo в бэкенде, это конечно не разумно. Но когда речь например про CMS, или про какую-то медийную платформу — это хорошее решение, для части данных.

Про транзакции: Есть множество примеров слабо связанных данных, для которых консистентность не сильно важна. Mongo и большинство noSQL решений реализуют 2 свойства из CAP теоремы: availability и parition tolerance. И они открыто говорят что консистентность — это как правило не к ним. Нужна консистетность: да, нужна Postgres, или Oracle DB. Это ни как не говорит о том, что отсутствие схем в Mongo — плохо.
Потому что данные живут отдельно, а приложение — отдельно. У меня к примеру есть пяток сайтов, которые ходят в одну базу. У каждого своя схема. Но новости у них общие, и они берут их из одной общей таблицы в одной из схем. Двойное хранение(не описание) схемы защищает от возможных проблем рассинхронизации. К примеру в новостях стало одним полем меньше, или его переименовали, поменяли тип. Часть сайтов обновилось, а один забыли. С одиночным описанием — лови сюрпризы.

Тоже самое с двумя воркерами ходящими в одну БД. Один обновили, второй забыли, или обновили, но не так как нужно. БД гарантирует, что данные будут такие, какие они должны быть.

Отсутствие схемы — это не плохо. Но нужно в действительности достаточно редко(и там NoSQL действительно незаменимы), а пихают их куда ни попадя. Впрочем это применимо к любой «модной» технологии. Как только что-то стало модным, его начинаю везде пихать, кичится этим, писать в резюмешечках, гордо сообщать кандидатам на собеседованиях и всякое такое.
Ну вообще хорошим вариантом было бы микросервис новостей выделить, и уже за его интерфейсом прятать возможные изменения схемы. Согласитесь, очень плохо, что 5 приложений лазят в одну базу.
2 еще понятно — (backend и www-frontend). Но не 5. От такой архитектуры никакие схемы не спасут.

И что будет в итоге в базе, если приложение 1 мигрирует схему до версии А, приложение 2 до версии Б, и они не совместимы друг с другом. Как вы будете решать конфликт?

Тут не в монге проблема, а в изначальной архитектуре. Вы рискуете получить мусорную базу, на одном из апдейтов.
Я рискую получить ее на СУБД без схемы. SQL база следит за тем, что бы «неправильные» данные не попали в базу. Да, остаются некоторые кейсы, которые не покрываются, но в львиной доле(и самых критичнх) случаях неправильный запрос в БД просто не пройдет и выдаст ошибку, которую сразу будет видно и будет легко устранить. NoSQL БД тихо прожует это и не заметит, пока у вас от этих данных не заглючит на сервисах, которые как раз в порядке. В SQL если очень хочется, вообще можно сверить свою схему со схемой БД при запуске, если очень хочется быть уверенным что все ок.

А чего плохого в пяти приложениях в одной базе? У меня и так пять одинаковых приложений, которые отличаются только контентом(но не кодом) и пересекаются по одной таблице. Городить сервис ради одной таблицы о о трех-четырех столбцах? С еще одним отдельным деплоем? Проблема решается в три строчки кода, нет никакой нужды городить целый сервис для этого.

Ну и опять же. Что вы будете делать с воркерами? С накатыванием из дампа БД(вы же их делаете, да?) не от той версии приложения? Таких мест уйма. И если можно относительно безболезненно верифицировать данные между компонентами системы, их нужно верифицировать. А в большом количестве случаев еще и необходимо.
В таких случаях надо всего-навсего генерировать не схему БД по схеме уровня приложения — а наоборот. Хотя, конечно же, SOA предпочтительнее.
Дело в том, что помимо предпочтений и идеалов красоты архитектуры есть еще и историческая наследственность и экономическая(и практическая) целесообразность. Другими словам — реальный мир.
И схемы баз данных — это не какой-то атавизм прошлого века, как может показаться, это меньшее зло, отточенное ни много ни мало, поколениями программистов, уже десятилетиями набивающих шишки на подобных описанным мной проблемах.
Можно конечно отбросить этот опыт, и снова топтать старые грабли. Но зачем?
Вы сейчас с кем спорите?
В базы руками приходится лазить значительно чаще чем того хотелось бы.
Как правило, что бы исправить ошибки тулинга для миграций)
Совершенно согласен. Нечего в базы руками лазить, если только конфиги самой Бд праивить, но не данные и тем более не схемы.
А разве нельзя в той же MySQL получить схему? Ну и работать с ней на уровне приложения.
Не удержался. «Перфораторы – отстой, пробовал им шурупы закручивать, когда шкаф собирал, обматерился, отвёрткой удобнее». «Шуруповёрты – отстой, пол часа дырку сверлил в монолитной стене»… У каждого инструмента есть свои задачи и прежде чем выбрать инструмент, надо понять, что тебе от него надо, умеет ли он это делать и как делает, инструкцию почитать.

И любое утверждение типа: «этот популярный продукт – отстой» лишь говорит об компетенции и профессионализме оратора…
Бывает, что плюсы инструментов на начальных стадиях жизни продуктов превращаются в минусы позже.
Это недоработки архитектуры, т.е. кода на этапе проектирования либо было непонятно, что нужно, либо было непонятно как работает инструмент, либо и то и другое вместе. Я не говорю про эволюцию продукта, когда в процессе развития он меняется и приходится менять инструменты, но меняют их не потому, что они плохие, а потому, что поменялись задачи и, соответственно, меняется набор инструментов для решения этих задач.
Очень интересная статья, спасибо. Хотя у меня случай обратный. Так и не удалось сделать на Postgress систему из 30 млн. записей с высокой доступностью данных. То есть система имела характер, когда примерно 5% записей использовались регулярно, а остальное очень редко. В итоге, при обращении к редким записям начинался процесс подгрузки данных с диска, который занимал до 30 секунд. Повторная выборка занимала уже 5 секунд, третья — 150-300 мс. Но до третьей уже редко кто доходил. Потом мог быть перерыв неделю, за которую эти данные «вымывались» из памяти, и все повторялось сначала.

В итоге отползли полностью на ElasticSearch. Там в худшем случае прогрев занимает 3-5 секунд. Побочная плюшка — на прогретых данных мы забыли что такое «сотни миллисекунд» и оперируем только десятками милисекунд.

В итоге постгресс используется в основном только для хранения логов и аналитики, поскольку SQL-запрос конечно написать проще, чем JSON-запрос. :)
А не рассматривали вариант ступенчатого стораджа?
Часть данных на чем нибудь вида redis/tarantool, основной сторадж postgres?

зы. второй пример из презентации youtu.be/RnEsn2qiRN8 — очень похож на ваш случай.
Так и было. Сначала был вариант Postgress + файловая система. То есть тупо агрегированные данные записывались в определенную систему папок в сгруппированном виде. И раз в месяц стирались. Кстати, до сих пор считаю этот вариант самым предсказуемым по скорости при первом доступе к данным.

Потом Postgres + Redis. В этом случае все почти здорово, но если диск безразмерен, то память конечна, и это несколько напрягало. На диск я могу данные класть хоть по крону (так сказать, предподготовка кеша раз в неделю). Но отдавать под Редис пару десятков гигов смысла нет. Е раз нет — проблема прогрева все равно остается.

ElasticSearch эту проблему решил. Сейчас этот вариант — основной. Конечно, есть опасения в стабильности решения, доверия PostgreSQL больше (старый конь борозды не портит), но с другой стороны — выгоды от применения просто неожиданно полно перекрыли бизнес-требования, что решили рискнуть.
Мы вот PostgreSQL используем как основное хранилище, а по мере изменения/добавления данные синхронизируем в ElasticSearch в денормализованном виде. Соответственно PostgreSQL дёргается только когда надо что-то поменять, на чтение используется ElasticSearch. До кучи получили полнотекстовый поиск по чему угодно.
Тоже сначала так думал. А потом решил — зачем лишнее звено? Данные в моем проекте проходят несколько последовательных массовых обработок, и храня промежуточные значения в ElasticSearch все равно получил значительный прирост в скорости. Вот и подумал — рискну, сделаю без PG вовсе.
Видимо что то не так с запросом… из таблиц с 30 миллионами, при правильной схеме данных и запросе данные выгребаются менее чем за 1 ms.
В принципе, на 50-150 мс я выходил (о чем и пишу выше). Проблемы были именно при первом обращении к данным. После кеширования индекса все было замечательно.
UFO just landed and posted this here
30 миллионов это не большие объемы, любая БД (MySQL/Postrges/MongoDB) это тянет безе проблем. У вас видимо либо проблемы с индексами, либо за запросами.
until we replaced the primaries of the cluster = пока мы не сменили первичный сервер в кластере
Как минимум, не один первичный сервер. А потом, что это за такие сервера в кластере?
вы изначально выбрали базу данных, которая не удовлетворяет вашим требованиям. чего вы ожидали?
А чем такие красивые картинки рисуете?
Подскажите пожалуйста, статистические графики такие приятные кто рисует?
кажется это NewRelic
Sign up to leave a comment.

Articles