5. Когда выбирать MongoDB

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

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

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

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

Бесструктурность

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

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

Для меня настоящее преимущество бесструктурной архитектуры — это отсутствие установки и сведённые к минимуму расхождения с ООП. Особенно это чувствуется при работе со статически типизированными языками. Я работал с MongoDB как в C#, так и в Ruby — разница бросается в глаза. Динамизм Ruby и популярная реализация ActiveRecord уже ощутимо сокращают расхождение объектной и реляционной моделей (object-relational impedance mismatch). Это не означает, что MongoDB — плохое решение для Ruby, напротив. Скорее я думаю, что большинство Ruby-разработчиков видят MongoDB как небольшое улучшение, в то время как разработчики, пишущие на C# или Java, видят пропасть разделяющую MongoDB и их подход к манипулированию данными.

Драйвер преобразует объекты языка в BSON. BSON и JSON не взаимозаменяемы: даты, ObjectId, десятичные и целочисленные типы требуют явного учёта. Проверьте сериализацию и обратное чтение важных значений, особенно денежных сумм и больших идентификаторов.

Запись

Гибкие документы могут быть полезны для журналов событий, но скорость записи зависит от индексов, нагрузки, дисков и требований к подтверждению. Write concern задаёт, какое подтверждение требуется от сервера. Запись без подтверждения (w: 0) — явный компромисс с потерей сведений об ошибках; её нельзя представлять универсальным преимуществом или безопасным значением по умолчанию.

Кроме указанных факторов производительности, при логгировании как раз может оказаться полезной гибкая структура данных. Наконец, в MongoDB есть такое понятие, как ограниченная коллекция (capped collection). До сих пор мы создавали обыкновенные коллекции. Мы можем создать ограниченную коллекцию с помощью команды db.createCollection, включив флаг capped:

//ограничиваем размер коллекции до 1 мегабайта
db.createCollection('logs', {capped: true, size: 1048576})

Ограниченная коллекция имеет фиксированный бюджет; при заполнении старые документы вытесняются. Не используйте её как единственное хранилище обязательного журнала аудита. Опции size и max, ограничения обновления и порядок чтения проверяйте по документации своей версии. Для хронологии событий храните явную временную метку: порядок вставки не равнозначен бизнес-времени события.

Результат подтверждённой записи и ошибки проверяются через API выбранного драйвера или оболочки. Исторические db.getLastError() и Ruby-опция safe не являются современной схемой обработки ошибок. Не ослабляйте write concern ради скорости без обоснованных требований к потере данных.

Устойчивость

Журналирование, репликация и подтверждение записи решают разные задачи. Не копируйте старый параметр journal=true и не отключайте журналирование по общему совету о скорости. Проверяйте конфигурацию своей версии, выбранный storage engine и write concern. Резервные копии и проверка восстановления нужны отдельно: репликация может воспроизвести ошибочное удаление.

Полнотекстовый поиск

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

Транзакции

Изменение одного документа атомарно. MongoDB также поддерживает многодокументные транзакции на replica set и шардированных кластерах. Самостоятельный standalone-сервер не равнозначен такому развёртыванию. Транзакции требуют корректных read/write concern и имеют стоимость; они не отменяют проектирование модели данных.

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

Обработка данных

Для группировки и преобразования данных используйте aggregation pipeline. Стадии фильтрации, группировки и проекции можно комбинировать, а план выполнения — проверять. MongoDB MapReduce помечен устаревшим начиная с 5.0; следующая глава сохраняет объяснение модели map/reduce и добавляет pipeline для той же задачи.

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

Геопространственные данные

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

Инструментарий и зрелость

Оценка зрелости MongoDB как «молодой технологии» относится к времени первого издания. Для текущего проекта проверяйте поддержку функций и жизненный цикл конкретной версии. BSON содержит Decimal128: прежнее утверждение об отсутствии десятичных чисел устарело. Это не отменяет требований к округлению и точности денежных расчётов; типы данных нужно выбирать явно.

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

В этой главе

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

Дальше в книге6. MapReduce и агрегация →
Karl Seguin · перевод @jsmarkus · CC BY-NC 3.0 и авторы