Pull to refresh

Comments 245

Просто кто-то не умеет готовить mongo и взялся за проект, не прочитав про него ни строчки.
Может вы укажете на явные ошибки в доводах автора для тех, кто не является специалистом по базам данных?
> Документ — это большой JSON объект
Это не обязательно большой обьект

>Вот пример документа одного сериала, Вавилон 5
Почему вы решили что это оптимальная модель данных?
Почему например документ не может из себя представлять описание эпизода?
А другой документ описание сериала. Причем эти документы можно разнести по разным коллекциям.

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


и потом банальная задача «удалить сериал» при отсутствии поддержки целостности превращается в многоступенчатый процесс:
— удаляем все связанные записи из коллекции с сериями
— удаляем все связанные записи из коллекции с отзывами
— удаляем запись из коллекции сериалов

а если записей много, и где-то этот процесс навернулся — у нас остается неконсистентность

при этом задача «удалить актеров, на которых больше нет ссылок из сериалов» — становится достаточно нетривиальной
так про это и статья: если нужна реляционность (а она чаще всего нужна) — Mongo не очень хороший выбор, так как реляционность придется делать на уровне кода, а это чревато массой проблем
Ох, зря выходит удалил. Ну да ладно. В целом я согласен, просто довольно глупо выглядит выбор инструмента, который не подходит, а потом выставление этого инструмента виноватым в том, что он не подходит.
ну вот люди сделали ошибку, написали статью о том как ошиблись (я думаю статья не новая явно)
если бы 5 лет назад эта статья попалась бы нам на глаза — мы бы тоже не выбрали монгу в качестве основной БД

а 5 лет назад в монге помимо ограничений «by design» было еще очень-очень много недоработок и хреновостей, которые приходилось героически преодолевать. сейчас с этим уже намного-намного лучше
А в статье про конкретные баги ни слова. Две технические проблемы, описанные в статье: отсутствие ACID транзакций и отсутствие джоинов. Они и по сей день никуда не делись. Статья описывает опыт полученный в 2010-2012 годах.
ну про старые баги (часть из которых можно было считать фичами) — это уже история, вспомнил в порядке ностальгии :)
люди рассказали, как они ошиблись с выбором инструмента, и пишут в заголовке «никогда не используйте этот инструмент».

Разумно, да.
люди описали свою ошибку, потом описали в каких случаях не использовать этот инструмент. заголовок немного не соответствует статье, но это не отменяет полезности самой статьи
Кто вам сказал что удаление это тривиальная задача? И кстати, удаление гораздо более не тривиально в реляционных данных.
ну вот в реляционной СУБД пример с сериалами — решается сильно проще. большая часть остального — тоже.
Вы путаете проще и привычнее. А кроме того забываете про связанность данных и как следствие переиндексирование реляционных таблиц. При этом когда вы сравниваете реляционные базы с документарными вы не учитываете возможность разных полей описания для разных сериалов и серий. Например если сериалы у вас делятся на типы (боевики, семейные, для взрослых и т.д.) то в некоторых из типов будут присутствовать дополнительные поля описания (например количество трупов) а в других нет.
Я не путаю ничего. Проще — это когда все делается 1 запросом, который гарантированно или выполнится, или нет, не сломавшись на пол-дороги и не оставив базу в неопределенном состоянии.
А дополнительные поля описания — вполне можно вместить и в реляционную модель. Это будет не так красиво как в Mongo, но 5 лет использования Mongo на серьезных наборах данных четко убедили меня в мысли, что целостность — все-таки более приятный бонус.
Если у вас запрос с кучей JOIN'ов на удаление данных, которые из-за этих самых JOIN'ов, выполняется, скажем, 2 минуты, и сервер, например, зависнет/упадёт/выключится — то у вас тоже будет падение на полпути и нецелостность данных. Побъются таблицы. Так в чём же разница?
любой нормальный сервер с поддержкой транзакций даже после сбоя операцию выполнит. монга кстати тоже выполнит операцию если сбой был на сервере БД

проблема монги в том, что те же каскадные удаления надо делать на программном уровне, и сбойнуть все может (с куда большей вероятностью чем падение сервера) именно на уровне приложения, и тут уже журнал операций сервера БД не поможет
Mongo выполнит, но в определенных кейсах.
В 32 битной версии по дефолту не выполнит.
Разница в том, что не побьются.
1) При правильном проектировании реляционной базы в запросе скорее всего не будет ни одного джойна.
2) Не смотря на 1) есть вероятность что он будет выполняться 2 минуты, но при таком количестве зависимостей у вас в NoSQL проблем будет никак не меньше(как и описано в статье, вам придется или массово дублировать данные, или реализовывать контроль целостности данных в коде)
3)Ваша фраза о том что «побъются таблицы» говорит о полном непонимании того как работают реляционные базы. И сводит ценность вашего комментария к абсолютному нулю.
Расскажите ка мне, как это вы будите писать запрос по вытаскиваю данных из НОРМАЛИЗОВАННОЙ БАЗЫ без join-в?
По вытаскиванию — скорее всего никак. Речь шла об удалении. Если внешние ключи и индексы расставлены с умом, то удаление не потребует джойнов.
С удалением я полностью согласен. А вот с select-ом…

P.s. I'm so sorry, зачитался комментариями и забыл что parent-comment был об удалении.
В реляционных структурах я бы вообще не вспоминал слово «удаление» (если только речь не идет о переносе данных в архивные таблицы). Методов скрывать данные от приложения/пользователя достаточно много
Покажите как правильно сделать тот же пример с сериалами.
В комментарии выше я дал направление. Если хотите вот вам схемы для документов:
СЕРИИ (все поля не обязательны)

{
«название серии»:
«название сериала»:
«id сериала»:
«название сезона»:
«id сезона»:
«актеры сериала»:< array[,...] >
«актеры серии»:< array[,...] >
«описание»:…
}

— КОММЕНТАРИЙ (все поля не обязательны)

{
«название серии»:
«название сериала»:
«id сериала»:
«название сезона»:
«id сезона»:
«актеры сериала»:< array[,...] >
«актеры серии»:< array[,...] >
«Комментарий»:…
}

Хотите помощь в реальной задаче — пишите в личку.
А вы прочитали статью до конца? Там как раз описан кейс про список эпизодов и сериалов для всех актеров. Как эта структура решает проблему?
Простой выборкой по полю «актеры сериала»
и тут вдруг нам понадобилось сменить название сериала (с ошибкой было, например)…
И что? Меняйте. Имя сериала это описательное поле, это не индекс. А что если в реляционной базе понадобится внести дополнительное поле описания? Это же надо будет изменить структуру таблицы для всего что уже записано и переиндексировать потом все с начала. Да везде есть нетривиальные задачи, но документарные базы позволяют их решать проще если у вас большое количество данных. С небольшим количеством данных удобнее работать в реляционной модели, но если данных много и приходится учитывать операции индексирования, то документарная модель лучше справляется.
И что? Меняйте. Имя сериала это описательное поле, это не индекс

в скольких коллекциях и скольких документах вы его храните во имя денормализации? а если что-то сломалось по дороге?

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

зачем? обычно это можно решить без такого размаха

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

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

Допускаю, что мой комментарий очень глуп — я не специалист в MongoDB совершенно. Поэтому, возможно, спрашиваю очевидные вещи. Рассчитываю на снисхождение :).

Что вообще хранится в поле «актёры сериала» — имена актёров, id или и то, и другое?

Если имена — то все проблемы, описанные в статье, ваши. Вы уверены, что распознаете, что «Одри Хепбёрн» и «Одри Хепберн» — одна и та же актриса, причём та же самая, что и «Хепбёрн, Одри», и «О. Хепберн», и «Хёпберн О.», но не та же самая, что «Хёпберн К.»?

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

Если и то, и другое — не совсем вижу, получится ли преодолеть проблемы вариантов «только одно» или «только другое».
«актеры сериала»: array('actor_id (from actor document)' => 'Actor Name (for caching reason),.....)

.find({ «актеры сериала.actor_id»: {$exists:true} )
Подозреваю, что актёры это некий документ с ид на отдельную коллекцию актёров, что то в виде:
{
«имя»:
«фамилия»:
«id актёра»:
«id фото»:
}
Ошибка автора в том, что не нужно делать из нереляционной СУБД реляционную. Если уж вас так пугает дублирование данных, то нужно создавать отдельный документ и использовать dbref на него. Они поспешили переходить на mysql просто не подумав. Увы но так делаются многие проекты.
Кстати, а что произойдет с производительностью в случае использования большого количества dbref в документе?
Он не критично мал. Dbref ссылается на _id, а это по сути индексирование поле.
Но тогда по сути это ничем не отличается от ручного find-а по _id?
Насчет реализации точно сказать не могу, но скорее всего именно так.
Советую глянуть по этому поводу статью docs.mongodb.org/manual/reference/database-references/

А для автора статьи можно было бы кинуть ссылочку на docs.mongodb.org/manual/data-modeling/#SchemaDesign-EmbeddingandLinking. Жаль что это перевод
Этот вопрос в статье рассмотрен. Как только появляются DBRef_ы сразу появляются джоины, которые работают медленно. То есть теряется собственно смысл использования NoSQL, так как единственное неоспоримое преимущество перед реляционными СУБД — скорость.
Вы забываете про преимущество в виде отсутствия схемы. При этом NoSQL не всегда быстрее хорошо организованной реляционной СУБД.
Это призрачное преимущество. В программе все равно будет схема (типы), в живом приложении взять и поменять схему не выйдет. Прямо в статье есть пример — были сериалы, где актеры включены в документы сериалов. Потом понадобилось поменять схему — вытащить сущность актеров в отдельные документы.

Как отсутствие схемы помогло? Похоже что никак.
Чаще всего отсутствие схемы — миф. Схема присутствует, но рассыпана по коду, изменение схемы — изменение в коде (причем код становится запутанным и раздутым из-за необходимости поддерживать старую схему для уже существующих данных и т.д.). А такое неявное присутствие схемы делает сложным понимание вообще структуры и взаимосвязей данных — нет никакой мета информации, как на уровне БД о колонках и их типах, ссылочности, ограничениях и т.д. А это, следовательно, увеличивает вероятность багов со стороны разработчиков, которые, могут по коду упустить какие-либо изменения схемы, сделанные другими разработчиками и т.д.
Отсутствие схемы — это произвольные json документы, но никак не бизнес-сущности в приложении. Любые бизнес-сущности, засунутые в один JSON — это полноценная, но жутко неудобная схема в неявном виде
Вы можете в своем приложении создать программно схему, создать entity и ей следовать.
Речь о том, что никто не заставляет это делать.
Простой пример.

Есть база ресторанов и гостиниц.

1. Реляционная БД. У ресторана свои поля, у гостиницы свои поля. Значит 2 таблицы. Если надо выбрать и то, и то, например, по метро, то это минимум 1 JOIN. Если это пользовательский выбор, то нужны стейтменты.
И вот, чтобы добавить новое поле для, например, ресторанов, то мы меняем структуру таблицы, а затем ищем в коде где испльзуются стейтменты и добавляем это поле туда, иначе наши «SELECT * FROM table WHERE metro=?» и им подобные уже не работают. Помимо формы редактирования, например.

2. Документоориентированная БД. Все сущности можно хранить в 1 БД (коллекции), с готовым индексом по метро. Добавили в рестораны новое поле — просто в форму (метод) редактирования его внесли. Всё. Всё остальное как работало, так и работает.
Открой для себя ef code first в c#. Добавляешь пол в класс и автоматом добавляется в базу.
в случае с ресторанами и гостиницами можно использовать подход Core Entities & Hiers — 1 таблица — «гео-объект» (название, адрес, тип,… ) +1 таблица на каждый из типов сущностей: рестораны, отели, чебуречные,…
А вы хоть раз такой проект реализовывали, чтобы такое предлагать? И какое количество пользователей в сутки это выдерживало? и был ли там поиск по нескольким параметрам?
Использую такой подход в самописной LCMS для создания и хранения учебных объектов с учетом вложенности и типов. Отдельно таблица «узел контета» с названием, вложенностью и другими общими параметрами. И отдельно по таблице на каждый из видов узлов (их с десяток). Сейчас больше 200k объектов, полет нормальный. Правда задач поиска по нескольким категориям не возникало, особых нагрузок нет.
Отсутствие схемы нужно редко и в очень малых количествах (в большинстве случаев).
Причём в большинстве случев достаточно завести поле «extra_data», куда пихать json (индексировать, правда, не выйдет).
Ну а сейчас в postgresql уже есть родной json.
В PostgreSQL 9.4 (релиз осенью) индексировать выйдет. Там совсем родной json (тип назвали jsonb) с эффективным хранением, возможностью индексирования и всякими клёвыми операторами (не все из них, правда, войдут в стандартную поставку).
Я бы сказал, единственное действительно неоспоримое преимущество — шардинг из коробки. Преимущество в скорости (по крайней мере по сравнению с последними релизами PostgreSQL) под большим вопросом.
А шардинг зачем нужен? Надежность он не увеличивает (по сравнению с РСУБД), скорость записи тоже (вся запись идет в master), только скорость чтения. Да еще и нарваться на неконсистентное состояние с шардингом проще в разы.
Когда база перестанет влезать в дисковый массив — тогда очень нужен :)
С минусами я не спорю, но если БД реально большая — деваться особо некуда.
А добавить дисков в массив не? Зачем еще один сервер ставить? Там где вопрос касается терабайтов данных никто отдельные диски в серваки не пихает.
Я не вижу смысла спорить. Если вам не нужен шардинг — рад за вас :)
Если кому-то он нужен (наверное, очевидно, что у разных проектов разные потребности, и мы не сможем рассмотреть все случаи), то его наличие — это плюс.
Just because you can it doesn't mean you should.

Реальная потребность в шардинге настолько редка, что когда она возникает фичи СУБД имеют довольно слабое значение.
Дисков можно и доставить. А вот доставить процессоров в этот сервер будет более сложной задачей. Ибо вертикальное масштабирование не всегда возможно.
А процессоры зачем? Тяжелые запросы надо кешировать, тогда вся производительность упрется в скорость записи на диски. Почитайте про архитектуру StackOverflow. Там посоны живут без шардинга, и неплохо живут при их объемах. И основная нагрузка на СУБД — запись.
а вы почитайте про архитектуру Badoo, например, и вы поймёте, что не всё можно вместить на один сервер. У Stackoverflow не такая уж и большая нагрузка — всего 216 запросов в секунду, и это при их 25 серверах.
Вы не делаете Badoo, и даже SO не делаете, а он прекрасно живет на одном сервере БД. Зачем шардинг?
я делаю игры. И в них может быть и больше 216 запросов в секунду. А может и не быть. Поэтому я лучше заранее спроектирую свою систему и заложу в неё возможность шардинга, и по началу у меня просто будет один шард — пока его будет хватать. Зато когда (если) игра выстрелит, то я очень быстро отмасштабирую всю систему.
Делать шардинг только в первый раз сложно. Когда всю систему отладил один раз, второй раз уже гораздо проще, и оверинжиниринг небольшой.
А с чего ты взял что 216 это потолок? Я делал системы, где в базу приходило 800-1500 запросов в секунду. но потом прикрутил кеш и получилось 50 запросов в секунду. Вообще считать запросы к базе без конкретной архитектуры смысла не имеет.
я про потолок ничего не говорил. Я взял данные из последней статьи про StackOverflow, и из числа 560 млн запросов в месяц вычислил, сколько запросов в секунду. Понятно, что пиковое значение у них в 5-10 раз больше. Плюс, в статье написано, что сервер ы загружены на 10%. Просто комментировал ваш аргумент про StackOverflow.
Ну то есть в пике будет успешно выдерживать 2160 запросов в секунду. Этого мало для ваших игр? При наличии хорошо продуманного кеша потребность в шардинге у вас не возникнет ИМХО.
напоминаю, что StackOverflow живёт на 25 серверах, из которых 4 (четыре) — серверы баз данных.
К тому же, кэш помогает ускорить чтение, а вот запись масштабируется либо увеличением ресурсов сервера (вертикально), либо шардингом (горизонтально). Кэш в этом случае не поможет. А в играх запись — очень частая операция.
Я не пойму, о чём мы спорим. Вы хотите сказать, что шардинг — напрасная придумка, и все базы можно впихнуть в один сервер? Или что мне (и всем читателям этих комментов) никогда не светит выйти за границы одного сервера?
Из 4 это кластеры. Реально все запросы SO обрабатываются одним серверов, и остального StackExchange — другим. Но сверху построен слой кеширования из-за которого до базы долетают от силы 10% запросов, большинство из которых запись.

Типичное интерактивное веб-приложение (вроде соцсети) иримеет соотношение чтения\записи примерно 98\2. Для сайтов где контент больше потребляется, чем создается, соотношение еще больше в сторону чтения. И итоге если у вас в базу попадает 200 независимых запросов на запись в секунду, то чтений происходит примерно 9800, и это при загрузке СУБД в 10%. До таких масштабов далеко не каждый проект доживет.

Если же у вас сценарий стриминга данных, то смысла нет сравнивать с SO. Нужно буферизировтаь данные и заливать через bulk insert или аналогичные технологии. На sql express мне удавалось 20,000 строк в секунду писать.

Действительно не многие здесь смогут упереться в ограничения одной машины, чтобы пришлось шардить. А даже если придется, то вопрос функций СУБД будет иметь далеко не первое значение.

Кстати учитывая что у монги database-level lock на запись, то она действительно без шардинга не справится, даже с 216 в секунду, особенно при обеспечении хоть какой либо-надежности.
Peak is more like 2600-3000 requests/sec on most weekdays.

Как хорошо, что я не видел статью на хабре, а сразу читал оригинал.
> скорость записи тоже (вся запись идет в master)

Наверное, прежде чем вот так рассуждать, надо сначала почитать хотя бы краткую документацию, да? Master — это в репликации. Шардинг это капельку о другом. Хотя продакшн шардинг и включает в себя репликацию, но это никак не относится к тому, что вы хотели сказать.
Тут я привел пример где работа с DBRef будет быстрее «джойнов».

теряется собственно смысл использования NoSQL,
А что если у вас много данных и одна таблица размазана на 10 серверов, как вы в реляционной СУБД будете делать джойны и транзакции?
Много это сколько? У меня было около 2 ТБ в одной таблице на одном сервере. Зачем надо размазывать на 10 серверов? Горизонтальное масштабирование рсубд небходимо на таких объемах, которых 99,999% разработчиков никогда не увидят. Это происки вендоров NoSQL, для которых 10ГБ уже достаточно, чтобы горизонтально масштабировать.
А это от специфики приложения сильно зависит. Приложение не обязательно должно быть таким уж и сложным. Представте, что вы пишите систему интернет-аналитики, или сбора морниторинговых данных. В таких системах бывает 100 тысяч запросов на запись в секунду и больше. Без шардинга такую задачу просто не реально решить, так как просто упретесь в скорость дискового массива.
А зачем сразу в базу писать? Обычно для потоковой записи сначала пишут в промежуточный буфер (тупо на диск), а потом вливают в СУБД. Если realtime данные нужны пользователю, то пишут в кеш в памяти. Не обращал внимания что GA и Яндекс Метрика показывают реалтайм данные очень ограничено, а полную статистику только за прошедший день?
Можно, вопрос только зачем. На cassandra таже задача решается проще. Так можно про любую базу сказать, что оно хорошая — я тут рядышком ручками допишу, что она не умеет, а потом сложу обратно :)
Нет смысла пытаться заменить кеш базой данных и наоборот. Если поставить cassandra для всего, то получится и не кеш, и не база. А если захочется согласованности данных, то все равно придется лепить РСУБД. Об этом в статье было.

А если выбирать куда писать поток событий — на диск или в кассандру, то я выберу диск. Тупо дешевле и надежнее. Просто на каждое событие создается файл, а потом раз в час\день\месяц сливается все в субд.
>Нет смысла пытаться заменить кеш базой данных и наоборот.

Еще как есть, почитайте про cassandra, ее именно так и нужно использовать.
Дайте ссылку чтоли? Если есть смысл, то почему всеподряд не используют? Кассандра, на сколько мне известно, не поддерживает ссылочную целостность, даже несмотря на транзакции, поэтому для многих сценариев она непригодна.
lambda-architecture.net/ — вот на самом деле ссылка для наиболее общего подобного случая.

И там Кассандра занимает место [2] (master dataset), которое Вы отводите файлам (у которых с ссылочной целостностью тоже не очень, насколько я понимаю).
Сваливание в файлы невозможно ускорить по записи втрое, подключив ещё несколько узлов. И репликация (replication_factor у Кассандры) на несколько узлов с автошардингом — нетривиальная для файлового хранилища задача, на самом деле.
Ниче не понял честно говоря. С чего вы взяли что файлы — это master dataset? Master dataset_ом всегда будет РСУБД, ибо поддерживает целостность. А вот для ускорения некоторых операций могут быть и промежуточные хранилища — файлы, очереди итп.

Зачем нужно то, что по ссылке я не понял.
master dataset — это место, куда валится всё-всё что на входе, до разбора и преобразований.
(Уточню на всякий случай: мы обсуждаем систему, которая более-менее в реалтайме выдаёт аналитику для десятков тысяч событий в секунду. Логи там, отчёты всякие.)

Использовать под мастер датасет РСУБД безумие. Потому что транзакционная природа тут ни к чему, ибо данные не мутабельны. Одна строка — одно событие, бывают только insert или select. За транзакции для этого мы заплатим скоростью вставки и большей централизацией (хотя бы для координации блокировок), что сделает всю систему хрупче.

У нас на уровне этого самом мастер датасета ровно одна задача — проглотить и надёжно сохранить все входящие. Много входящих.

Потом уже эти данные пересчитываются пачками (при помощи канонического Map/Reduce) и, в качестве бонус-трека, потоково (при помощи стрим процессора какого-нибудь, типа Storm).
Производные данные как раз-таки хорошо хранятся в РСУБД. Это именно они читаются с клиентов, и именно тут транзакционность может быть критичной. Потому что производные данные — это суть свёртки, и для них на сцену выходят апдейты имеющихся рядов.
Теперь понял, на сайте это ни разу не очевидно. Лучше бы raw dataset назвали, ибо в bi называют master data справочные данные, которые потом используются для сведения многих систем.

Вот только не понял чем кассандра лучше записи в файлы.
>чем кассандра лучше записи в файлы

Шардинг из коробки, гибкое управление фактором репликации, устойчивость к потере узлов, автобалансировка записи без единой точки отказа, линейное масштабирование (по объёму хранилища и скорости записи) при добавлении новых узлов, возможность добавлять новые узлы «на лету» (с оговорками, правда).
Ах, ну да. И Хадуп по ней бегает как по родной, без предварительной выгрузки данных в HDFS.
Вот неплохое введение: habrahabr.ru/post/204026/

>Если есть смысл, то почему всеподряд не используют? — да вообще часто довольно используют. Кассандра штука специфичная, но кому нужно много писать, часто выбирают ее.
Что касается кеша, я честно гвооря не вижу как это может помочь. В таких системах обычно не хранят все поступившие данные, а аггрегируют различные счетчики по каким-то интервалам (например часам) и потом выполняют запросы аггрегирующие типа типа group by по дням, неделям и так далее. Кеш в этом случае должен быть не тупым key-value, а умной штукой, с поддержкой умных апдтейтов и запросов, а это уже получается опять какая-то база нужна.

Я думаю на практике никакие кеши не используют, и работает все отстойно, как вы и написали, с задержкой в сутки.
Агрегируют что? Перед тем как агрегировать данные надо куда-то записать. При большом потоке самый лучший вариант — диск локального сервера. Быстрее и надежнее (одновременно) сложно что-то придумать. Если писать только в не-durable хранилище, то велика вероятность потерять ченить.

А что касается кеша, то тот же redis поддерживает операции типа append и pub\sub, с которыми легко получить нужный результат.
Нет, не обязательно записывать все. Вот представьте летят показы баннера, просто инкерементируется значение счетчика, соответсвующее показам за какой-то час, получается данные аггрегируются на лету по часам и надежно сохраняются, что и позволяет добиться риалтаймовости, о не-durable хранилище речь не идет. Cassandra позвоялет укзать кворум записи, таким образом данные будут пробублированны на W серверах (W — задаем сами), это будет надежнее, чем писать на диск одного сервера. Да и сложного ничего не вижу. А вам еще придется фоновым процессом разгребать все это дело :)

Redis — совсем не подходит для хранения временных рядов. Там нельзя будет сделать поиск по диапазону дат и аггрегацию.

А как потом получить значение сколько баннеров было показано в ночь с пятницы на понедельник?

А в redis не нужно делать агрегацию, её надо в базе делать или в olap. Redis нужен только чтобы показать хиты за последние 15 минут\день.

Я делал систему статистики для SharePoint (встроенная довольно убогая) и главное было сделать реалтайм мониторинг (бесполезная фича, но красиво показывать было). Выкрутился именно так как описал — база в MS SQL для статистики и кеш для «реалтайма», правда промежуточного хранилища не было, события агрегировались в памяти приложения и пачками заливались в MS SQL.
>А как потом получить значение сколько баннеров было показано в ночь с пятницы на понедельник?

Запросить за диапазон дат, и в коде просуммировать полученные счетчики, это если ad-hoc. Но «иделогически» правильно в таком случае писать еще один счетчик, типа количество показов за каждые 12 часов. Т.е. обычно приложение в cassandra пишет сразу кучу таблиц, где данные группируются уже как надо.
Если я не ошибаюсь, то mongo умеет DBRef, который хоть и не замена join-а, но некоторыми коннекторами работающая в подобной роли.
присоединяюсь к вопросу.
Как вы решаете проблемы запроса дополнительных данных по их BSON id
Делаю дополнительный find. Разве не логично?
По сути дела, за меня это делает Spring.
равносильно дополнительный SELCT в mysql
Не равносильно. В mysql два select-а можно сделать в одной транзакции.
можно, но имелся в виду именно дополнительный запрос
В mysql я могу обернуть сколько угодно запросов в транзакцию и получить гарантированно консистентные данные. В монге — не могу. Единственный способ получить консистентное состояние базы — хранить всю информацию в одном документе (либо использовать глобальные блокировки, что сведет производительность к нулю)
Более того, монга по умолчанию не гарантирует что будут прочитаны только что записанные данные, особенно при репликации.
При репликации этого и РСУБД в общем случае не гарантируют.
Mirroroing+синхронный коммит таки гарантируют.
Здравствуй, CAP-теорема. :)
Часто на практике видели network partitioning? Я за 10 лет ни разу. А проблемы несогласованности — хоть отбавляй.
Был случай, когда надо было синхронизировать данные между серверами, расположенными на разных континентах, вот там-то я дерьма наелся. :)
Ты имеешь в виду мульти запрос?
я ничего такого не имею в виду, простая транзакция.

псевдокодом:

db.beginTransaction();
var a = db.prepare("select * from a where id = ?", 1).execute().fetchRow();
var b = db.prepare("select * from b where id = ?", a.bId).execute().fetchRow();
db.commit();
Это зависит от задачи, например у меня в ajax приложении я отправляю сырой документ comment, в котором есть ссылка author,
на клиенте вывожу его с пом. Angular, примерно так: <div>{{comment.text}} <a href="{{#get comment.author -> homePage}}">{{#get comment.author -> name}}</a> </div>
Т.к. этот автор в 95% случаев уже закеширован в браузере, то имя и ссылка сразу подставятся, в остальных случаях произойдет автомтическая подгрузка автора и вывод в нужные места.

А в комментарии может быть ещё много ссылок, которые мы не «джойнили» т.к. не было необходимости.
В итоге мы имеем такие плюсы: меньшая нагрузка на БД (нет джойнов, меньшее кол-во обращений в БД), меньшая нагрузка на сервер за счет того что часть (или весь) рендеринга будет происходит у клиента, меньшее кол-во передаваемых данных.
Кейс интересный, но по факту вы держите кеш на клиенте?
А при отсутствии данных идет шторм запросов в базу, или все таки собирается кумулятивный запрос (но это уже больше вопрос по ядру самого Angular)?
У меня в одном из проектов собирается кумулятивный запрос в течение 100-300 мс, после этого летит на сервер одним «пакетом», в итоге ссылки на одни и те же объекты не порождают дополнительных запросов, объектов.
А на сервере эти документы выбираются одним запросом, если они из одной коллекции.
То есть для джоина надо вытащить записи на клиент, в смысле браузер, а потом сбегать на сервер и забрать связанные записи? Это хорошая идея? Это должно быстро работать?

В протоколе OData есть возможность делать Join прямо с клиента, и он прекрасно прикручивается к РСУБД.
Предположу, что интерфейс у Вас очень долго грузится, особенно когда надо загрузить связанные данные после первого-второго запроса.
То же самое можно сделать на сервере — параллельная загрузка несвязанных данных. При этом это будет невероятно быстрее: отсутствуют ожидания на клиенте, страница рисуется разом, кеш будет действовать для всех запросов.
Ну и как то сложно мне видится составление такого кумулятивного запооса, поддержка batch на уровне апи, разбор потом такого запроса.
Нет, грузиться быстро, хотя для SPA и медленная загрузка допустима.
Ну и как то сложно мне видится составление такого кумулятивного запооса
Ничего сложного, а профит ощутимый (по аналогичной причине на некоторых сайтах множество js собирают в один js файл).
кеш будет действовать для всех запросов.
А если данные возьмутся из кеша браузера, то это будет ещё быстрее чем запрос на сервер.
Только начал работать с angularjs, #get это функционал из коробки? Не могу найти информации, или это псевдокод?
Абсолютно с вами согласен, автор 'зная' что монго не реляционная бд, пытается хранить в ней связанные данные и негодует.
Ребят, а за что мои пост получает минусы?
UFO just landed and posted this here
Вы бы сначала разобрались в моделировании данных, разделили бы коллекции, и сделали бы все правильно, а потом бы уже кричали какарул монго мне данные того сего. Ну не разобрались в нереляционной модели, привыкли реляционным базам, ну бывает, зачем сразу столько пафоса «Вы никогда не должны использовать MongoDB»?

— Я создаю веб-приложения. Я участвую в 4-6 разных проектах каждый год, то есть создаю много веб-приложений. Я вижу много приложений с различными требованиями и различными потребностями хранения данных. Я разворачивала большинство хранилищ, о которых вы слышали, и несколько, о которых даже не подозреваете-------.

Либо у вас за этой рутиной не хватило времени разобраться в моделировании данных под монго, либо… одно из двух.
Это не ко мне, а к автору. А вы можете привести пример «как надо»? На примере тех же сериалов или соцсети.
Да уж =) Автор спроектировал корявенькую архитектуру да еще и выбрал абсолютно не тот инструмент под нее. Но ведь конечно, если коньки не едут по асфальту, то это коньки виноваты, а не одевший их индивидуум.

P.S. Нисколько не защищаю MongoDB кстати, погоняли ее в тестах и оказалось, что практически для всех задач есть более эффективные инструменты.
Довольно банальные вещи, на самом деле, хотя сам по себе кейс, безусловно, интересен. Спасибо!
Заголовок абсолютно желтый. Нет ничего специфичного для MongoDB, кроме как конкретный попробованный пример документо-ориентированной базы данных. Такой критикой можно ударить по бОльшей части NoSQL продуктов, которые, как показывает практика, могут успешно использоваться и без непосредственной связи между таблицами.
Для MongoDB довольно много специфичного:
1) Отсутствие ACID транзакций
2) Отсутствие джоинов в любом виде (как минимум на момент написания).

Сейчас появились более продвинутые движки NoSQL которые лишены обоих недостатков и проблемы, описанные в статье, гораздо менее актуальны.
ACID транзакций и джоинов нет также и в Riak, Cassandra, HBase, что не делает их менее «продвинутыми».

Значит у них будут те же самые проблемы. Но есть например RavenDB, где есть ACID и джоины, причем с автоматическими индексами. С ним указанных проблем не будет.
будут те же самые «проблемы» только тогда, когда Вы попытается наложить реляционную структуру на них
Я пытался работать с RavenDB в таком стиле. Кое-де он просел хуже SQL Express, но особого геморроя не доставил. Транзакции в нем есть, за несогласованность боятся не надо. Джоины делаются индексами на стороне БД и описываются в C# обычными Linq запросами. Если данные индекса устаревшие, то он честно об этом говорит и можно предусмотреть UI для этого.

Проблемы в общем есть, но совсем не страшные. Правда RavenDB денег стоит и багов еще дофига. В продакшн пока страшно, а для блогов самое то.
>денег стоит
>для блогов
Взаимоисключающие параграфы.
Да, поэтому на практике и не используется. Может баги починят, тогда можно будет ченить серьезное писать, а пока — увы.
Что-то мне кажется, что бд на сисярпе исключительно под .NET взлетит невысоко, пролетит недалеко.
Сделай тесты, опубликуй результаты, интересно будет глянуть.
Я не про скорость, а про масштабы прикладного использования. Мало кто из здравомыслящих людей будет крутить бд на mono под никсами в продакшене. В итоге имеем бд, претендующую на звание next-gen nosql, и функционирующую на ~30% серверов. Что-то тут не сходится.
Ну почему же. У Монги целая масса всякой специфики: начиная с глобалных блокировок на запись и заканчивая отсутствием какой-либо компресии хранимых данных и рекомендацией авторов Монги использовать короткие имена полей в объектах (что для меня выглядит глупо и несерьезно).
Абсолютно согласен. Но разве на один из этих пунктов автор указывает?..
Автор указывает, что у Монги хватает нюансов, о которых обычно на всяких уроках/тренингах/ознакомительной документации обычно не упоминается, но которые делают использование Монги во многих проектах неуместным. И я в этом с автором согласен. В том числе потому, что у самого был проект, где в качестве одной из БД была выбрана MongoDB и впоследствии этот выбор был признан неудачным.

А заголовок, конечно, слишком желтый.
Чего не хватает MongoDB — это операции соединения как в SQL, которая позволяет написать один запрос, объединяющий вместе ленту активности и всех пользователей, на которых есть ссылки из ленты. В конечном итоге приходится вручную делать джоины в коде приложения.

С pymongo это можно сделать подключив нужный «son_manipulator», и «джойны» будут происходить автоматический на уровне «драйвера». Под Ruby тоже не должно быть такой проблемы.

Ещё один из вариантов: отправлять клиенту документ как есть, а «джойны» производить в браузере со списком закешированых пользователей, это особенно удобно для ajax приложений. Таким образом уменьшается нагрузка на БД и кол-во передаваемых данных клиенту.

PS: Статья не нова, и у меня есть ощущение что её уже переводили на хабре.
Искал переводы, но не нашел. Подобных статей в одно время было очень много.
С pymongo это можно сделать подключив нужный «son_manipulator», и «джойны» будут происходить автоматический на уровне «драйвера». Под Ruby тоже не должно быть такой проблемы.


Не в этом дело. В любом случае, pymongo или что-либо другое будет сначала получать документ на клиент, смотреть на что он ссылается и подтягивать это следующими запросами.
Увидев заголовок аж вздрогнул испугавшись. Почитал статью и выяснил, что заголовок имеет к ней очень отдалённое отношение. :(
Правильно было бы назвать «не начинайте новый проект с использованием MongoDB», но в таком виде заголовок завлекает больше читателей.
Нет, корректнее было бы «Правильно проектируйте хранение данных, а то может случиться конфуз» — это никак не относится ни к MongoDB, ни к любой другой БД, независимо от её типа.

Приходилось видеть и на MySQL такое, что еле-еле работало и хрипело «пристрели меня…», но это ж не значит, что MySQL плохая.
Есть в статье несколько Mongo-специфичных моментов. Например неконсистентность из-за отсутствия транзакций и полное отсутствие джоинов на стороне СУБД. Без этих недостатков проблема была бы не столь велика.
Погодите, но ведь если мы, проектируя хранение данных, изначально закладываемся на эти «фичи» Монги, это не должно стать сюрпризом.
А если это стало сюрпризом, значит хреново проектировали, и незачем с больной головы на здоровую перекладывать — Монго делает ровно то, что она делает.
Странно было бы, например, обвинять Redis в отсутствии, скажем, JOIN'ов — это ведь даже в голову никому не приходит. Так почему можно обвинять MongoDB в отсутствии вещей, об отсутствии которых сказано изначально в документации?
Правильно, если все заранее знать, то проблем не будет, но, процитирую автора:

Я говорила об этом так, как будто вся информация была очевидна, и команда Dispora просто не в состоянии провести исследование, прежде чем выбрать.

Но это было совсем не очевидно. Документация MongoDB говорит о том что хорошо, и вообще не говорит о том, что не хорошо.Это естественно. Все так делают. Но в результате потребовалось около 6 месяцев и много жалоб пользователей и много расследований, чтобы выяснить что мы использовали MongoDB не по назначению.


На момент описанных событий хайп вокруг MongoDB и NoSQL вообще перекрыл здравый смысл. Даже сейчас попадаются люди, которые не понимают чем грозит отсутствие транзакций.
В документации монги до сих пор очень много «белых пятен». Например узнать про database-lock при записи очень сложно, об этом написано одно предложение. Про проблемы, которые индуцирует отсутствие acid (по сути после записи нет гарантий что оно вообще записалось) вообще ни слова. Некоторые маркетинговые материалы монги откровенно врут, выдавая желаемое за действительное. Вот тут подробнее: hackingdistributed.com/2013/01/29/mongo-ft/
Как по мне, решение данной задачи через кеш — это полумера. В какой-то момент придется выбрать или, что данные будут сильно рассогласованные, или кеш будет сбрасываться на каждый чих и толку от него будет 0. Я думаю, что самый правильный способ решить такую задачу — это денормализация данных. Когда кто-то добавляет комментарий к посту, это должно привести к запуску фоного процесса (который может быть параллельным) к записи комментария в документ «лента» каждого пользователя, кто должен это увидеть. Тут будет и eventual consistency и не будет проблем с инвалидацией, так как pull данных мы заменяем на push.
В статье про это детально написано. И про фоновый процесс, который может (и будет) падать, и про денормализацию. Читайте внимательнее.
И там же есть очень хороший вывод — при хранении денормализованной ленты событий MongoDB база данных фактически превращается в кеш, который категорически не отвечает требованиям надежного и согласованного хранения данных.
Так вот я именно с этим выводом не согласен, в своем комментарии я имел ввиду использование единой базы. MongoDB можно использовать и как первичное хранилище, и как кеш одновременно. Да, для этого нужно уже использовать references, и ничего плохого в их использовании я не вижу, если references считываются только фоновым процессом, а на пользовательские запросы вынимаются документы целиком из разных подготовленных коллекций.

ИМХО, они там себе придумали ограничение — не использовать references, превравтив базу в кеш, и сами с ним героически боролись.
Н проблема, покажите как надо.
Изначально цель была сделать быстро. Ибо джоин семи таблиц в PostgreSQL это совсем не быстро. В итоге пришли к тому что база превратилась в кеш.

Покажите как надо делать чтобы этого не случилось.
Да так же как они сделали по сути, только вместо PostgreSQL + кеш, все делать в MongoDB, но используя таки внешние ключи. Еще раз, все заморочки у них связанны исключительно с нежеланием использовать внешние ключи. Просто не надо использовать эти ключи для выборки данных на пользовательских запросах, а использовать для построения ленты фоновым процессом. Если бы они не отказались от внешних ключей, база бы не превратилась в кеш.
Я все равно вас не понимаю — джоины в Mongo отсутствуют, ручные джоины медленные. Быстрее работает тоже самое в PostgreSQL. Зачем тогда MongoDB?

Как только начинаешь нормализовывать данные MongoDB и NoSQL вообще идет лесом. А без нормализации появляются проблемы. Об этом собственно и статья.

Что вы хотите сказать? Что можно сделать быстро и хорошо в MongoDB, тогда просто покажите. На примере тех же сериалов.
Пример с сериалами — вполне можно было сразу хранить cast_members не как встроенную коллекцию, а как массив references. Все данные вытаскиваются двумя запросами: вначале вытаскиваем сезоны, у них в одну коллекцию складываем id-шки на всех актеров, вытаскиваем еще одним запросом актеров, я так делал, это работает достаточно быстро. Еще не факт, что join-ы быстрее :) Расскидать актеров по эпизодам можно, если у каждого актера хранить массив эпизодов, где он снимался. Заметьте, что запрос документов по массиву id — операция, которая отлично работает в распределенном окружении, posgresql со своими join-ами тут вообще садится в лужу. Если этого не достаточно, можно потом денормализовать и добавить фоновым процессом в каждый сезон еще и список актеров.

Резюмируя — я считаю mongodb полноценным хранилищем, однако нужно учитывать особенности документной схемы и распределенного хранения данных.

Нужно тест сделать, так не очевидно. Взять тот же General Hospital c его 1200 эпизодов.

Запрос документов по id в распределенном окружении можно сделать на любой субд. А вот сделать запрос не по id, или джоин на стороне базы, чтобы не перетягивать коллекции в память приложения уже не так просто.
Сделать запрос по id можно, но монга имеет встроенную поддержку, там в id кодируется номер узла. А еще монга позволяет удобно хранить массивы, это еще один плюс.

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

Проблема шардинга не техническая, сделать один диапазон ключей в одной базе, в другой диапазон в другой — не проблема вообще. Проблема начинается когда нужно делать джоины между шардами. Это будет одинаково плохо работать и в монге и в любой другой СУБД. А джоины делать придется, запихнуть все нужные данные для любого запроса в один доумент на практике нереально.
Да ничего не мешает закодировать, просто как бе из каробки поддержка :)

Насчет «запихнуть все нужные данные», да, конечно предел у техники с массивом внутри документа есть, и он 16 мегабайт :) Но для таких больших данных я бы уже смотрел на тяжелую артелерию, вроде cassandra.
Это в постгресе? Я sql server пользуюсь, там хоть гигабайты храни.
Это в монге, там ограничение 16Мб на документ.
Почему если говорят о реляционной БД, значит всегда надо использовать джойны? Мы можем ее использовать как NoSQL тоже — то есть не использовать джойны и делать выборки по primary key.
Если надо загрузить связанные сущности после первого запроса — делаем следующий запрос последовательно. Если что-то можно загрузить параллельно — делаем это.
И получается, что такая архитектура очень здорово ложится на кеши, и запросы занимают ооочень малое время — потому что из базы тянется мало данных и очень быстро — запросы элементарные, а потом еще кеш подключается.
Использую монгу для сваливания всякого статистического хлама и прогона по этому map/reduce. Отлично своё дело делает.

А вот для веб-приложений, да, переносить хаос в БД вместо того, чтобы сделать схему — это глупость.
А мапредьюсить чем-то посторонним?
По состоянию на 2.4 встроенный джаваскриптовый M/R был чудовищно медленным и не параллелился.
> Стручки общаются с помощью API на основе протокола HTTP (сейчас это модно называть REST API — прим. пер.)
Пер. непр.

Не всякий API можно назвать REST API.
В теории да, но на практике всё подряд называют REST API. Думаю родившись Diaspora сегодня, там 100% был бы REST API, хотя не отличался бы совершенно от того, что было придумано в 2010.
Вброшу: а в PostgreSQL 9.4. можно будет колонки типа jsonb (с эффективным хранением и шустрыми индексами по ним), куда можно будет сваливать как раз такие данные с не шибко явной схемой. Олег Бартунов на конфе PGDay прямо сравнивал с Mongo по скорости и функциональности и сравнение было не в пользу Mongo.
В постгресе нет атомарных операций с документами, ведь так? Если да, то это сильно хуже монги.
В постргесе есть транзакции. По сути атомарные операции с любым подмножеством данных.
Транзакции есть, но набор операций над данными довольно бедный.

Что бы постгресе атомарно добавить элемент в массив, который хранится в поле типа json нужно руками делать locking, либо pessimistic через select… for update, либо optimistic через дополнительно поле с версией и циклом, который проверяет обновилась ли запись или использовать serializable уровень изоляции и ловить в коде ошибки сериализации.

В монге нужно просто сделать $push.

Или вот еще пример: сделать upsert. В постгресе нужно пытаться вставить, ловить constraint violation, и тогда пытаться делать update.

А монге просто параметр upsert=true.
А зачем все в json хранить? Храни просто в колонках значения. Так и индексы будут работать.
Индексы есть и у json полей в постгресе. Просто это частый кейс — хранение данных без фиксированной схемы, вроде интернет-магазинов. Собственно для этого и есть тип json в постгресе.
Хранение без фиксированной схемы — неявная схема? Ибо совсем без схемы это блоб, с которым приложение ничего сделать не может. А если схема неявная то её можно сделать явной. В интернет-магазинах основная функция — подбор по параметрам. Её удобнее всего делать на поиске, типа lucene, а сами данные хранить проще в рсубд, чтобы можно было легко получить самые продаваемые товары и подобные выборки.

В том случае при редактировании всегда будет. оптимистичная блокировка и из приложения уже готовый json будет прилетать в базу.
Ну с люсином же вы как-то работаете? Так же и работа с документами в монге без схемы происходит. Например как с ассоциативными массивами.
Нет, совершенно по разному. Для монги и большинства других NoSQL движков основная операция — выбор по ключу. Для lucene основная операция — полнотекстовый запрос с атрибутивными фильтрами. Для полнотекстового индекса данные — набор «векторов» с произвольными значениями, в которым можно делать запросы по любым параметрам. Никаких связей и структуры внутри полнотестового индекса нет. Поэтому он может только как инструмент для сложных запросов работать, а не пытаться подменить основное хранилище.
Вообще в монге есть схожая функциональность — multikey indexes. Они индексируют сразу массив аттрибутов, получается примерно как в lucene. Так что все это довольно близко.
Почему же нельзя сделать upsert? можно одной командой:
WITH u AS ( UPDATE table SET field = 1 WHERE id = 2 RETURNING id ) INSERT INTO table (id, field) SELECT 2,1 WHERE NOT EXISTS (SELECT 1 FROM u);
ну и/или вариации если надо что-то другое… так кстати можно одновременно за одну команду вставить в несколько таблиц

и никаких ошибок
Если генерить sql руками, то да. Вы мне расскажите, какая orm умеет такое сама:)? А в монге все в порядке, все через красивый api без выкрутасов с трехэтажными запросами. Я именно про это говорю, атомарность есть, но операции бедные, апсерт так или иначе самому приходится реализовывать.
Ого! Я его использую, а о таком не знал :)
Любая ORM, основанная на полноценном Query Builder, который сводит все к SQL AST, притом под SQL подразумевается конкретный диалект. Если каких-то возможностей новых версий не хватает, всегда можно легко дописать.

Например, python-овский SqlAlchemy близок к идеалу.

Да, разумеется, речь идет об ORM, реализующих паттерн Data Mapper. ActiveRecord неполноценен по определению, хотя и из него с правильным подходом можно «выжать» многое.
>(автор — девушка)

gandjustas, зачем эта отсебятина? У вас проблемы с девушками?
У меня — нет, а почему это вас задело? Может у вас проблемы?
Меня задевает шовинизм любого рода. И неточность перевода, в меньшей степени.
На протяжение всего чтения статьи всё больше утверждался в мысли, что автор винит не столько выбранную базу данных, сколько архитектуру приложения и модель самих данных. Вот только говорить о своей некомпетентности, обвиняя себя в неправильном построении архитектуры, — никто не будет. Вот и появляются такие статьи. Жалко только, что хорошие продукты попадают под желтые заголовки.
Тогда покажите как правильно надо было. В статье целых две системы описано. Как можно было бы их хорошо сделать на MongoDB?
Исправьте, пожалуйста, ошибки. Перевод ужасен. Хотя смысл предложений и ясен, но читается с трудом. В конце концов, тема переводов многократно поднималась на хабре, в том числе и совет про то, чтобы дать почитать статью паре знакомым\друзьям\коллегам перед публикацией.
С радостью, статья длинная все равно ошибки проскакивают, а профессионального редактора нет. Некоторые вещи переведены тупо гуглтранслейтом. Напишите конкретно что не нравится и где ошибки — поправлю.
Ошибок много — практически через каждый абзац. Думаю, они заметны и без моих указаний. А вот по поводу гугл транслейта — зря Вы так. Это лично мое мнение — но если что-то делать, то делать качественно.
На этом предлагаю закрыть нашу ветку диалога, т.к. нас уже стали минусовать)
Как же использовать джойны реляционной базы, если данные в Diaspora физически распределенные?
Может каждый экземпляр кладёт в свою базу данные, пришедшие в виде уведомлений?
Как это влияет? Пользователь обращается всегда к одному Сручку, и данные для выполнения запроса пользователя хранятся в этом Стручке.
Вполне разумно тогда считать локальную базу кэшем. Хотя, да, валидировать такой кэш крайне сложно, проще синхронизировать нормализованную структуру
Все правильно говорите, но в такой архитектуре нет ничего, кроме кеша. От этого и проблема с консистентностью. От этом тоже в статье написано.
Переводчику спасибо, а вот нытье автора напоминает что-то вроде — «Ах какое же сложное функциональное программирование и какая сложная scala или F#», и следственно вывод — «пишите на кабале(cobol) он такой мужественный, теплый и ламповый».

От себя могу добавить, что один раз наблюдал за проектом соседней команды, так вот там лид на середине проекта решил спрыгнуть с mysql на lucene, по той лишь причине что им нужен был более продвинутый полнотекстовой поиск чем в mysql. Так вот одну задачу решили а потребность в связях осталась, теперь попробуйте себе представить как это получилось реализовать на чистом lucene и какие были последствия.

Вякала и плевалась вся команда после 2 мес опоздания и адской переработки по 12ч в день.

NoSql никогда не создавался для полной замены реляционных БД.
Создавался, смотря какие базы :) Просто вы совсем хардкорный пример привели, lucene это не база вовсе, это поисковый индекс, что вы от него хотите?
Да это точно, смотря какие. Приведу один контр-пример, в моей тек конторе я попал на код сделанный, именно, сиквел-маньяком. Управление (под)категориями ролей пользователей, выполнено на чистом ти-сиквеле с использованием рекурсии, а именно вид сам себя джоинил. Особенно меня порадовала проверка на уровень вложенности.

if(level = 99) -> exit

Типа при максимум 99, симулируем stackoverflow и мирно выходим. Только вот этот кудесник, не знал или забыл что уровень вложенности в таком чуде как сиквел сервере, четко запилен на 32 или 33, да простит меня Аллах. Вы не представляете как красиво все это чудо изрыгало проклятия в продакшене и падало.
Это не маньяк, а неуч. Маньяк бы CTE запилил. У него нет встроенного ограничения на глубину.
Да, а тимлиду тому двойка за такую грубую ошибку :)
Как-то проводили мозговой штурм по данным, их связям и тому, как всё это хранить. Пришли к таким выводам:

Ничего лучше id и ссылки на них для исключения дублирования не придумали.
Хранилище требует три основных типа данных:
— Документ, тип которого дополнительно определяется классом допумента
— Список из id, имеет атомарное добавление и опционально атомарное удаление
— Счётчик атомарно изменяемый целочисленный.
— Дополнительно не помешает Массив, аналогичен списку с произвольным типом.

Документ есть данные, относящиеся напрямую к объекту. Остальное хранится с помощью ссылки на списки.

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

Непротиворечивость и согласованное состояние гарантируется атомарностью (на уровне системы) добавления и удаления из списков и инкремента-декремента счётчика.

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

В итоге, условиям и требуемым возможностям удовлетворяли Redis и Couchbase, но и то, и другое требовало приличного объёма работы напильником и писания дополнительного кода.
Делать соцсеть и не юзать графовые бд. Они там архитектуру походу фейсроллили по клавиатуре.
А потом на БД жалуются, окей.
Приведите пример соцсети на графовой БД, которые можно посмотреть. Я бы с радостью глянул.
Я участвую в 4-6 разных проектах каждый год, то есть создаю много веб-приложений. Я разворачивала большинство хранилищ, о которых вы слышали, и несколько, о которых даже не подозреваете.

и такой FAIL с базой данных… что то тут не так)
а я давно говорил, что объектные базы можно выкинуть (только заминусовали меня почему то :) ), но почитаем, что пишет девушка — ей видимо в переводе больше доверия :)
В статье очень много воды и откровенной некомпетентности разработчиков «Диаспоры». И чтобы описать собственный фэйл, вовсе не обязательно тащить сюда свои дурацкие «стручки» — и без них понятно, ЧТО такое соц.сеть и все составляющие её сущности.

> Я говорила об этом так, как будто вся информация была очевидна, и команда Dispora просто не в состоянии провести исследование, прежде чем выбрать. Но это было совсем не очевидно.

Всё ровно наоборот: Это команда «Диаспоры» схватилась за новомодную технологию, реальное применение которой было СОВСЕМ НЕОЧЕВИДНО, и налепила косяков.
Перед прыжками в новомодные баззворды (NoSQL, WCF, WPF, SharePoint, Functional Programming, Web-services), нужно крайне критично проверять, ЧТО вам пытаются втюхать. Те же NoSQL состоят из документа, в который можно сунуть другой документ, и т.д. Но если два документа ссылаются на один (очевидный case), можно ли это физически сделать в NoSQL, не дублируя данные? Вот, оказывается нельзя. Каким же местом надо было думать, чтобы вот так спонталыку влепить Mongo в святая святых — хранилище данных?? РСУБД — это такая фундаментальная вещь, что шатать сию трубу имеют право только серьёзные технологии. Удивительная аналогия в том, что как PHP — уродливый братец Perl'а (переупростивший всё, чего не понимал), так и NoSQL — примитивный аналог RDBMS, реализовавший самое тупое хранение документов и потому так и остался на «тупом» уровне.

> Если эти разговоры, что произошли раньше, если бы мы взяли время, чтобы действительно понять, как клиент хочет видеть данные и что хочет делать с ним, то мы, вероятно, перешли бы PostgreSQL ранее, когда было меньше данных, и было легче.

ШТА?!..
я бы только из списка исключил WPF, хотя да мы его около месяца двух крутили, чтобы принять решение о его использованиии.
WPF получился неоднозначным продуктом и что я точно могу сказать, что НЕ ВСЕМ он подходит, особенно при немалом опыте в WinForms. Не всем — потому что всё-таки сложноват даже для «средних умов» (или требует весьма серьёзного обучения на курсах) и не всегда — потому что «мощь» WPF хороша только в простых случаях кастомизации. Увы, но даже (казалось бы) элементарный финт «хочу Expander с кнопкой справа» оборачивается целой простынёй кода ( patconroy.wordpress.com слэш 2008/12/18/restyling-the-wpf-expander-control/ ) — ТАКОЕ я никак не могу назвать «удобной технологией».
Так что хотите — выкидывайте из списка, но я вам точно скажу — торопиться переходить на WPF не стóит, придётся много чего «потрогать руками» и решить, есть ли от этого профит.
Если по большому счету, там профит в технике bind и резиновый интерфейс, + бонус — возможность засунуть в кнопку (к примеру) кучу других элементов, накрутить стили, что так любят дизайнеры… а так да, согласен времени отнимает много больше. Не очень согласен про простые случаи, смотря в каком смысле — выдавать простые окошки лучше WF, но а если надо чтото сложное и не стандарное то WPF пригодится
Полезного в этой книге чуть более, чем ничего. Фаулер в своем духе — описал в одной книге опыт предыдущих 5 лет и претендует на библию.
Книга то по сути не учебник, ибо научиться по ней чему-нибудь нельзя.
Также не справочник, ибо деталей не хватает, описание очень поверхностное.

Для расширения кругозора сойдет, но ссылаться на нее как на первоисточник я бы не стал.
На второй же иллюстрации нарисован граф. Почему же вы пытаетесь упихнуть его в документы или таблицы? Используйте графовые базы и не будете иметь проблем. Серьёзно. Расширяйте свой кругозор, вместо того, чтобы в очередной раз менять шило на мыло.
Поделитесь опытом использования графовых БД в реальных проектах.
А может просто надо выучить, что такое 3-я нормальная форма?
Некоторые утверждаю что графовые базы данных подходят лучше всего, но я не буду их рассматривать, так как они слишком нишевые для массовых проектов.

Таким образом социальные данные не являются документарными. Это означает что на самом деле социальные данные… реляционны?

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

интересно, что большинство современных графовых баз построено как надстройка над «документарным» или key/value ядром (OrientDB, ArangoDB, FoundationDB и т.п.)

ну и, да, у FaceBook база _тоже_ на MySQL крутится. так что все правильно ;)
Наконец-то, начал читать, комментирую по мере прочтения, похоже началось за здравие, закончилось за упокой — «Вот уже несколько лет мы знаем, что социальные данные не являются реляционными, если вы храните социальные данные в реляционной базе данных, то вы делаете это неправильно.»

Это еще чот такое, что за бред? Ладно эта девушка не обосновывает эту наистранейшую фразу, может ли тут кто -то это аргументировать?

«Таким образом, чтобы получить всю информацию о сериале нужно выполнить соединение пяти таблиц.» — и что?

«В реляционной СУБД это было бы соединение семи таблиц, чтобы вытащить все данные. Соединение семи таблиц, ух.» и опять и что? Но посыл не правильный,

«Пользователи имеют друзей, друзья имеют посты, посты имеют комментарии и лайки, каждый из которых имеет связан с одним комментатором или лайкером.»

Ни когда не нужно иметь все сразу — вам это разместить не где. Я не видел ни одного сайта где сразу видны вся иерархическая структура всех комментариев всех постов всех мои друзей — вы о чем вообще? Так может это все таки буду разные селекты когда вы смотрите своих друзей, когда вы смотрите их посты, и наконец когда вы смотрите их комментарии к посту?

И фиерическое продолжение:

«Пользователь имеет друзей, и каждый друг может сами быть пользователем. А может и не быть, потому что это распределенная система. Таким же образом, комментаторы и лайкеры также могут быть пользователями.»

Девушка узнала, что оказывается наивное представление данных оказывается не подчиняется 3-ей нормальной форме :) (училась бы в универе поняла бы это сразу :) )

«При этом подходе вместо встраивания данных там, где они нужны, вы даете каждому пользователю ID.» Начинается поиск костылей :)

«Дублируете ли вы важные данные (тьфу), или используете ссылки и делаете джоины в коде приложения (дважды тьфу), если вам нужны ссылки между документами, то вы переросли MongoDB. » — начало прозрения

«Если ваши данные выглядят как набор бумажных документов — поздравляю! Это хороший кейс для Mongo. Но если у вас есть ссылки между документами, то у вас на самом деле нет документов. MongoDB в этом случае — плохое решение.»

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

«Тем не менее, у нас есть хорошо понятное решение этой проблемы. Оно называется кеширование.» — соскочила с темы, ожидаемо… что ж прочту инапишу в следующем комментарии, что это не решение, а игра в прятки :)
А вообщем то все закончилось нормально — не плачьте :)

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

И так будет с каждым, кто не понимает, что такое 3-я нормальная форма :)

«После трех месяцев в разработке все прекрасно работало с MongoDB. Но однажды в понедельник на планерке клиент сказал, что один из инвесторов хочет новую фичу. Он хочет иметь возможность кликнуть на на имя актера и посмотреть его карьеру в телесериалах. Он хочет список всех эпизодов во всех сериалах в хронологическом порядке, в которых этот актер снимался. „

О! А что я вам выше написал (“Только забыла еще добавить, что как только понадобится искать не начиная с сериала»)? А девушка предсказуема… возможно она поняла свои заблуждения?

«Если эти разговоры, что произошли раньше, если бы мы взяли время, чтобы действительно понять, как клиент хочет видеть данные» — если бы у нее действительно был опыт как она описала вначале «Я разворачивала большинство хранилищ, о которых вы слышали, и несколько, о которых даже не подозреваете.» — то она знала бы, что клиенты всегда хотят видить данные в разных разрезах :) а соответственно без 3-ей нормальной не обойтись…

«Единственное, что удобно хранить в MongoDB — произвольные JSON фрагменты. „Произвольные“ в этом контексте означает, что вам абсолютно все равно что внутри JSON. „

И наконец, он пришла к выводу, о том, что было мне очевидно как только я решил попробовать монго — habrahabr.ru/post/144613/ и habrahabr.ru/post/144645/

где сразу получил комментарий “То есть ты взял и превратил монгу в тупой key/value store.» — Почти Да, точнее ActiveRecords, и девушка вам об этом тут и говорит (не доконца догоняя полученный опыт — надо еще поучится, и снизайдет на неё Буда) — и не только монго, а все, где нет 3-й нормальной формы — только на это и годится.

«Он сохранял произвольные данные, пришедшие от клиентов, в виде JSON. Это разумно. CAP теорема не имеет значения, когда в ваших данных нет смысла. Но в любом интересном приложении данные имеют смысл.»

и опять — этому и учат в универе, когда объясняют что такое первая нормальная форма :) Тяжело быть самоучкой, но она учится, а и еще хуже быть не пробиваемыми невеждами, которых тут на хабре достаточно :)

Я всё не мог понять, зачем нужен NoSQL. Теперь я понял, что его придумали люди, не осилившие SQL.
Верно. Но надо понимать, что они пытаются реанимировать сетевые базы данных, которые еще на заре были признаны не дееспособными, может для чего -то это и пригодится, но явно не в той же нише, что реляционные базы… А страх перед джоинами 5-20 таблицами столь смешен — видимо не слышали про оптимизаторы SQL запросов? Но или действительно не понимают как их делать?
А что делать когда БД перестает умещаться на один самый большой сервер который вы можете себе позволить? Расскажите в Facebook или Twitter что их данные можно хранить в 3ей нормальной форме и спокойно делать джойны для чего угодно, только оптимизировать надо. А то они дураки там в твиттере какой-то манхеттен разрабатывают, наверно в универе их не научили уму-разуму.
Раздуваешь огонь холивара. Тут много кто любит реляционные СУБД и будут отстаивать точку зрения, что они «лучше» до последнего. Никто не понимает, что у них просто разные целевые сегменты. Кстати, я всегда в пример привожу все крупные компании. Google, VK, Facebook, Twitter. У всех нереляционщина)
Но сейчас придут люди, которые любят Oracle,MSSQL,Mysql,Postgres и наставят минусов лишь, за то, что они любят их и я «дурак».
В большинстве случаев NoSQL не является основным хранилищем данных. Тот же твиттер, FB и VK пишут в MySQL.
Насколько я знаю, у VK своя nosql СУБД. У FB тоже вроде как все на касандре давным давно. Про твиттер не скажу.
Ага, «своя nosql СУБД» это аналог memcached, а хранятся данные таки в MySQL.
Cassandra в FB была применена для поиска по инбоксу (я даже ни разу этой фичей не пользовался), не нашел свидетельств что применяется еще где-то. А хранились данные всегда в MySQL.
У твиттера своя слой работы с данными, который не пишет напрямую в базу каждый твит, кроме того они заборели FlockDB, графовую базу, которая облегчает некоторые запросы. Но вот в качестве хранилища у них тот же MySQL.
MySQL у них у всех как движок, данные скорее всего денормализованы и по 10 таблиц там для построения стены никто не джойнит, а таблицы шардят между несколькими серверами. YouTube тоже использует MySQL: github.com/youtube/vitess. Тоже не в третьей нормальной форме естественно. Twitter использует разные хранилища исторически (MySQL, Cassandra и другие), но переходят на свою разработку Manhattan blog.twitter.com/2014/manhattan-our-real-time-multi-tenant-distributed-database-for-twitter-scale.

Каждой задаче свой инструмент, бросаться использовать Cassanda или Manhattan для системы инвенторизации закупок, где у MySQL запас по производительности будет x100 даже без оптимизаций — смысла нет. Но когда на хабре плюсуют комментарии в духе «NoSQL придумали люди, не осилившие SQL» — это странно.
Конечно странно, что плюсуют такие комменты, потому что большую часть NoSQL придумали как раз Google, FB, Twitter, в вот используют в основном те, кто не осилил SQL.

Проблема SQL в том, что довольно сложно обеспечить одновременно высокую скорость записи и чтения одновременно. Особенно при сильно денормализованных таблицах. Что-то одно — пожалуйста. К базам прикручивается кеш, а для записи используются механизмы bulk load.

NoSQL это по сути попытка совместить кеш и РСУБД, в разной пропорции в зависимости от конкретного движка. Но, к сожалению, такой гибрид в большинстве случаев оказывается хуже кеша+субд. Только в сценариях того же ФБ. гугла или твиттера может быть оправдано использование конкретной NoSQL, но не как хранилище общего назначения.
Ну, по общей логике — смотреть на положительный опыт Фейсбука мне имеет смысл когда у нас задачи сопоставимые (по нагрузке, по объёмам).
Это не так приблизительно для 100% участвующих в подобных дебатах в интернете.

Ну и да, между строк Вы подразумеваете, что NoSQL у Фейсбука не от хорошей жизни, а просто потому что данных слишком много и обычный SQL перестал справляться, а так бы он и был.
Собственно да, так оно и есть.
CAP теорема не имеет значения, когда в ваших данных нет смысла. Но в любом интересном приложении данные имеют смысл.

Означает ли эта фраза, что СМЫСЛ в СВЯЗЯХ?

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

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

Данные, без возможности связать их между собой или с другими наборами — это мусор.

>>что ценность для бизнеса есть только там, где есть связи.
Похоже что не только для бизнеса. Это более общее понятие.
Если нет связей, то и смысла нету. Вообще никакого. Не только бизнес смысла.
Смысл в связях и положении в графе.
Искусство выделять и представлять эти связи это и есть информационная инженерия.

Я так понимаю, что лучшее представление данных — ТРИПЛЕТЫ. Они всегда нормализованы ;))
SPARQL, триплет сторажи и все такое ;)
> Если ваши данные выглядят
> как набор бумажных
> документов — поздравляю!
…вы просто не умеете проектировать РБД.
Лично для меня schemaless в MongoDB — это возмоность не дублировать структуру данных в БД и в моделях данных. И да, schemaless далеко не единственная фича MongoDB. Да и темп появления новых фичей несомненной радует.
Я не работал с NoSQL, я просто фантазирую. Итак, если документы образуют дерево, то почему бы не использовать вместо голых числовых id символьные пути?
Где-то так и используют, в том же Редисе или Мемкеше принято именно так.
id это и есть путь в дереве. И он не числовой.
UFO just landed and posted this here
Да, всех косяков в одном комментарии и не перечислить. Поэтому написал целую статью :-)

habrahabr.ru/post/243431/

К сожалению, автор перевода отказался добавить ссылку на мою статью-ответ. Поэтому оставлю её здесь, в комментах.
Кстати, судя по ссылке, статья была написана всего год назад, в ноябре 2013 года.
UFO just landed and posted this here
А как же на счет этого примера реализации цепочки «друзей друзей друзей» с Mongo?

http://habrahabr.ru/post/88246/

алгоритм реализован на С++, скорость построения цепочки для 300 тыс пользователей 0.3 -0.5 сек
Очень крутая статья, рукопрещу. Есть правда местами недоработанный автоперевод.
Sign up to leave a comment.

Articles