Mongodb Или Как Разлюбить Sql



Введение Коллеги, при разработке приложений мы каждый день сталкиваемся с необходимостью гибкого хранения информации (обновление, поиск и т.п.

).

Класс продуктов, решающих этот круг задач, как мы все знаем, — это базы данных.

Но что это такое в нашем понимании? Многие люди ассоциируют «базу данных» с MySQL, таблицами и запросами SQL. И это меня устраивает до определенного момента.

Действительно, реляционные базы данных дают массу эксплуатационных преимуществ: поскольку данные тесно связаны, нет необходимости следить за целостностью базы данных.

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

Используя JOIN, можно легко выполнять сложные связанные выборки и получать данные о нескольких объектах одновременно.



Масштабировал-масштабировал, но не масштабировал
Однако когда вы вдруг понимаете, что одного сервера уже недостаточно, и вы хотите разнести базу данных по нескольким физическим машинам, первое, что предлагается — репликация master-slave, при которой запись идет на одну машину, а чтение — на несколько.

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

Данная схема очень сложна в реализации и содержит единственную точку отказа (т.е.

при выходе из строя одного сервера все его подчиненные быстро превращаются в динозавров).

Опять же, все эти уловки только увеличат количество прочтений.

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

Но тогда связь потеряется.

Либо придётся разбивать таблицу на несколько частей, сохраняя их в разных местах, по заданному закону (например, по ID), но это унесёт прелести JOIN в могилу.

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

Например, при использовании мастер-мастер мы будем платить с автоматическим приращением.



Спасут ли нас MemcacheDB и Redis?
Подобные решения «ключ-значение» существуют уже довольно давно.

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

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

: например, нет даже элементарной реализации времени жизни объекта времени (TTL), т.е.

нельзя брать и удалять сессии старше месяца.

Это не приносит результатов.

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

Более того, вам все равно придется вручную поддерживать кэш ключей, т.е.

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

При этом атомарности операций тоже нет: возникает гонка между получением объекта и записью его в кэш, CAS демотивирует нас своей производительностью.



Что делать, если мы хотим каталог товаров, похожий на Яндекс.

Маркет?

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

Допустим, мы используем реляционную базу данных, например MySQL. Что нам делать? Мы должны либо создать таблицу товаров, в которой будет содержаться и коэффициент масштабирования, и количество передач для велосипеда, и, например, показатель гибкости щетины зубной щетки (в этом случае мы упремся в поле ограничение для таблицы, иначе мы потеряем дисковое пространство, скорость и удобство), или нам следует создать таблицу типа Good_id, Key, Value и делать ужасные JOINы для выборки и поиска, не заморачиваясь о масштабировании.

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

У родственных женщин серьезная родовая травма.



MongoDB, говоришь?
МонгоБД - объектно-документная база данных острая как понос.

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

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

Коллекция — это именованный набор объектов, в котором один объект принадлежит только одной коллекции.

Объект представляет собой набор свойств, включая уникальный идентификатор _id. Свойство представляет собой комбинацию имени и соответствующего ему типа и значения.

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

Поддерживаются операции выбора (подсчет, группа, MapReduce.), вставка, изменение и удаление.

Между объектами нет связей; объекты могут хранить другие объекты только в свойствах.

Поддерживаются как уникальные, так и составные индексы.

Индексы можно размещать в свойствах вложенных объектов.

Поддерживается репликация (даже подразумеваемая), реализован отказоустойчивость.

Реализован MapReduce и шардинг.

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

В этом случае поиск будет осуществляться по индексам.

Острота MongoDB ярко выражена во вставках, они происходят очень быстро.

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

клиент — никакой абстракции над механизмом хранения.

Уникальный идентификатор — это не поле с автоинкрементом, а 12-байтовое уникальное число, сгенерированное на клиенте.

Таким образом, во-первых, нет проблем с синхронизацией реплик, т.е.

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



MongoDB + Memcached? Круче Бонни и Клайда!
С базой данных мы более-менее разобрались, теперь давайте подумаем, как можно все это дело закешировать, ведь мы хотим раздавать горячие пирожки на скорости Memcached! Во-первых, кэширование самих объектов.

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

Например, выбор объекта пользователя, выбор данного поста из базы Хабрахабра (аминь) и т.д. Как мы уже выяснили выше, перекладывать эту работу на приложение неразумно, ведь пришлось бы городить огород распределенных блокировок.

Пойдем другим путем, напишем асинхронное приложение, которое будет подключаться к MongoDB и, прикидываясь слейвом, будет получать лог изменений и сбрасывать изменения в Memcached (если объект содержит ключ в свойстве _key).

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

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

Кэширование запросов и аннулирование кеша должны работать немного по-другому.

Существует несколько подходов:

  • Кэш на определенное время.

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

  • Удаление кэша по запросу приложения.

    Подход довольно утомительный, но имеет право на жизнь.

  • Используйте службу блокировки, чтобы не выполнять одну и ту же работу дважды.

    Определенно это хорошо.



Недостатки, с которыми вам придется столкнуться.

  • MongoDB — довольно молодой продукт, и в нем есть ошибки (иногда ошибка сегментации, дамп ядра), появляются новые возможности и т. д. Я использую его в продакшене, но с осторожностью.

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

    Коммерческая поддержка также доступна.

  • Накладные расходы на хранение имен свойств.

  • По умолчанию максимальный размер объекта составляет 4 мегабайта.

  • На 32-битных машинах максимальный размер одной базы данных составляет 2 гигабайта .



Финита ла комедия!
Страница проекта - МонгоБД .

Найден эталон MongoDB против MySQL .

Эта статья рискует начать серию о MongoDB. В следующий раз я подробнее расскажу о шардинге, MapReduce и приведу живой пример.

Друзья, спасибо за внимание! Буду рад конструктивным комментариям.

Продолжение опубликовано: «MongoDB — готовим хороший кофе» .

Теги: #Web 2.0 #mongodb #базы данных #NoSQL

Вместе с данным постом часто просматривают: