MongoDb в действии — интернет магазин

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

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

    На хабре полно приложений в стиле «Hello World», так что инициализацию среды опустим и перейдем сразу к более продвинутым вопросам, а именно:
    • Почему удобнее хранить весь объект целиком, а не по таблицам?
    • Как бороться с реляциями?


    Почему удобнее хранить весь объект целиком, а не по таблицам?


    Для многих программистов все еще не очевидно, что выборка записей даже по Primary Key — это существенные затраты времени. Вроде как, знать такое и не нужно — бери себе таблицу, делай хранимую процедуру для поиска и можно больше ни о чем не переживать. Однако на практике объекты редко бывают плоскими, и любимый всеми механизм lazy loading очень быстро катастрофически ухудшает время работы системы.
    Вот несколько примеров комбинаций объектов, из моего реального опыта, за последние полтора года:
    — у товара есть произвольное количество картинок и видео
    — у товара произвольное количество характеристик
    — у категории есть товары, которые ее представляют
    — в случае наследования, которое добавляет новые свойства, мы либо теряем место в таблице, либо имеем дополнительный подзапрос
    — у объекта наименование и описание задано на произвольном количестве языков.

    Описать любой такой сценарий на C# не представляет труда; а вот сделать эффективный слой данных, который бы работал на сотне тысяч записей, будет затруднительно.

    В то же время, используя MongoDB, сохранить такой объект можно одним единственным вызовом:
    DocumentCollection.Save<T>(document);
    

    Загрузить его со всем вложенными классами тоже элементарно:
    DocumentCollection.FindOneById(id);
    

    К примеру, посмотрим на представление товара. За одно единственное обращение к базе данных — поиск по id категории и SeoFreindlyUrl, которое занимает 0,0012s (!) я получаю:
    — собственно свойства товара
    — его параметры (в данном случае всего два, но вообще их количество и типы произвольны)
    — изображения (повторно используется в категориях; 2 штуки, каждое имеет url + размеры)
    — видео (если бы были)
    — похожие товары (ссылки)
    — условия продажи (этот объект повторно используется в категориях и системных настройках для наследуемой конфигурации срока гарантии, возможности возврата)
    — производитель
    — Seo строки (заголовок браузера, мета тэги, сео текст)

    И могу сразу переходить к рендерингу.

    Для статистики: в таблице товаров на данный момент 154 тысячи записей; в среднем одна запись занимает 22KB; а размер таблицы — 4GB.

    Наилучший вариант считывания такого сложного объекта, если бы мы использовали SQL Server, была бы ручная сериализация всех свойств в xml. MongoDB же все это дает нам без каких-либо усилий.

    Вся наша система базируется на трех классах:
    — BaseMongoClass (Id, Title, LastChanged)
    — EntityRef (ссылка, содержит Id и Title, есть и более навороченные наследники)
    — BaseRepository, который реализует все необходимые методы для работы. Мы выбрали GetById, Get(запрос), FirstOrDefault, GetAll, GetByIds(по списку id), GetByEntityRefs(по списку EntityRef), Save, DeleteById, DeleteByQuery.

    Конкретный репозиторий просто наследуется от BaseRepository, указывая тип и имя коллекции (в терминах монго — это имя таблицы), и реализует какие-то операции уже уровня логики, такие как «найти товары по категории» и т.п.

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

    PS: Листинг базовых класов и репозитория можно скачать здесь.

    Как бороться с реляциями?



    Конечно же, реляций в монго нет. В проекте abo.ua мы применяем следующий подход:

    У товара может быть одна категория (у нас больше, но я немного упрощаю). В самом типе товара написано буквально следующее:
    public EntityRef Category { get; set; }
    [BsonIgnore] // Монго, не стоит сохранять это свойство 
    public Category CategoryValue
    {
       get
       {
          if (Category == null || Category .IsEmpty())
              return null;
          return AppRequestContext.Factory.BuildCategoryRepository().GetById(Category.Id);
        }
    }
    

    Когда мы меняем категорию, мы задаем Category. Когда нам нужен удобный способ узнать что-то детальнее о категории — мы обращаемся к CategoryValue.

    Для того, чтобы не терять время на вычитку и десериализацию категории, количество которых, конечно, и меняется относительно редко, CategoryRepository кэширует их все в оперативной памяти, в словаре ObjectId -> Category, скорость к которому превышает обращение к MongoDB.
    Когда хоть какая-то категория меняется, мы перестраиваем весь словарь.

    Можно, конечно, использовать Memory databases, однако эксперименты показали, что это принципиально медленнее, чем собственная память процесса.

    Другая проблема реляций — обновление информации в связанных объектах. Например, категорию изменили/удалили, но мы хотим чтобы у товара была актуальная информация:
    1. Всегда будьте готовы к нецелостной информации. Из кода приведённого выше, CategoryValue вернет null если такой категории уже нет; и вебсайт вернет код 404. Это еще простой сценарий. Когда мы вычитываем товары, мы сверяем свойства с определениями типов товаров: не удалили ли какое-то свойство? Не поменяли ли в нем список допустимых значений? Каково значение по умолчанию для добавленных в тип свойств? Звучит сложно, но на самом деле, когда все данные под рукой, мы успеваем просмотреть 1000 товаров в течении 0.1 с, чего вполне достаточно.
    2. После того как вы научили код «самозалечивать» целостность данных, становится легко написать код, который корректирует данные в базе. Выглядит он примерно так:
    var products = prodRepo.GetAll().OrderBy(p => p.Id).Skip(start).Take(portionSize).ToArray();
    prodRepo.JoinPropertyTypes(products); // собственно это метод кторый проверяет правильность 
    products.AsParallel().ForAll(p => prodRepo.Save(p));
    

    Осталось всего-то вызвать такой код (асинхронно) для всех объектов, которые были затронуты.

    В следущих частях


    Я опишу:
    • Есть ли жизнь без group by?
    • Как организовать полнотекстовый поиск с релевантностью в mongodb?
    • Конфигурация реальной среды
    Поделиться публикацией

    Комментарии 93

      +11
      Вместо того, что бы выгребать актуальные данные, Вы выгребаете «какие есть», а потом по «каким есть» выгребаете актуальные и проверяете на целостность? По сути пляшете от «кэша».
      Крайне любопытно будет почитать про поиск по параметрам вида «товар с присутствием красного и зеленого цветов, но отсутствием синего и желтого, остальные по фиг», а так же про вывод списков с сортировкой по любому из непрямых свойств товара (например по цветам в алфавитном порядке).
        0
        MongoDB не любит сортировать более чем 1000 записей без индекса, так что для больших категорий сортировку по произвольным параметрам мы запретили. Но для фильтрации секрет я раскрою:
        Категория с 2445 товарами
          +1
          Вообще я бы для фильтрации (как и для поиска) использовал люсен под эластикой, интересно как вы решили
        • НЛО прилетело и опубликовало эту надпись здесь
          +10
          >Как организовать полнотекстовый поиск с релевантностью в mongodb?

          Я для себя ответил таким образом: «Взять сфинкс». :)
            0
            вот кстати хорошее решение. сразу убивает несколько зайцев
              0
              Ага, и не только в mongodb.
                +3
                Еще можно ElastcSearch. К нему есть плагин под MongoDB. Профит по сравнению со сфинксом в real-time индексации
                  0
                  у сфинска тоже есть RT-индексы, но работа через mysql-интерфейс онли.
                    0
                    К сожалению у сфинкса для многих есть несколько минусов: у него плохая интеграция с пхп (то апи, что есть — ужасно) и его, судя по хабру, либо сложно готовить (либо он всегда выдает такой нерелевантный поиск). Люсен ему проигрывает в итоге только в прожорливости
                      0
                      Для RT-индексов есть доступ через MySQL-синтакс, я класс-прокладку на коленке написал и все работает (pdo на данный момент нельзя толком использовать из-за несовместимости).

                      Мне в принципе большая релевантность не нужна, поэтому по-второму пункту ничего сказать не могу.
                        0
                        Ну использовать sql, как говорят разработчики, стоит только для разработки, а само приложение все-таки должно работать через нормальное апи, но в пхп все это апи реализовано одним классом с минимальными возможностями
                          0
                          Через API с RT-индексами работать нельзя как я понимаю, вообще. Они только через MySQL.
                            0
                            > Ну использовать sql, как говорят разработчики, стоит только для разработки, а само приложение все-таки должно работать через нормальное апи,

                            ???
                              0
                              Хм, кажется я перепутал сфинкс с чем то:) то ли у эластики тоже есть sql-интерфейс, толи у кауч(или и вовсе тарантул), вот там только для «побаловаться» sql можно использовать
                                +1
                                Ага, понятно, "… а потом уже и анекдотов насочиняли" ;)
                          +1
                          Довольно обидно, что Хабр как рупор Российской ИТ индустрии так компрометирует Sphinx. На самом деле Sphinx способен искать гораздо качественнее Solr/ES/etc, особенно это касается русского языка. Вдобавок у к отсутствию прожорливости Sphinx гораздо быстрее индексирует документы, а бинарный протокол сильно экономит на пересвлке данных. Вот с RealTime у него действительно беда :( Приходится держать до 3-х дельта-индексов, при этом мёрджинг оказывается накладнее полного переиндексирования.

                          Те же программисты, что пишут Хабр реализовали поиск на сайте darudar.org гораздо качественнее. Там правда в 10-ки меньше нагрузка, но зато в 10-ки больше данных. Видимо просто сейчас на Хабре много более приоритетных задач, чем оптимизация поиска.
                            0
                            Кстати, а что с RT?

                            Пока что вроде все ок, но в хотелось бы быть готовым к проблемам :)
                      0
                      Я вот тоже давно задумываюсь о связке NoSQL + Поисковый движок (Sphinx/Solr/etc.). По сути RDBMS — это тот же key-value, плюс плохой (по сравнению с Sphinx/Solr) поисковый движок, плюс реляции с обеспечением целостности данных, плюс триггеры/хранимые процедуры, целесообразность использования которых в вэбе крайне сомнительна.

                      Целостность вполне можно обеспечить на стороне приложения. Sphinx/Solr решают все проблемы со сложными запросами. А вот что касается альтернатив реляциям, особенно M2M — вопрос для меня пока неисследованный. К примеру M2M связь пост → хаб довольно очевидна. Пост может находится в небольшом числе хабов, можно просто хранить их в документе поста как массив, выборку по хабу разрулит SE…

                      А если число связей велико с обоих сторон? А если у связи есть дополнительные данные (например пользователь → хаб, где есть роль, дата вступления и т.п.)?
                        0
                        Да, я конечно забыл о транзакциях. Это тоже больной вопрос…
                          0
                          Основной вывод по монго — жаль что я его не сформулировал в самой статье — что структура базы намного ближе к коду, с ней проще работать, чем sql. Хочешь реляции? Пожалуйста. хочешь словари — пожалуйста, хочешь массив с идексом — да без проблем.

                          Особенно удобно в связке с основнанной на json библиотекой knockout, которая обеспечивает взаимодействие с пользователем.
                        +1
                        Как хранить в MongoDb дерево с произвольным уровнем вложенности, с возможностью прикрепления в качестве узла ссылки на другой узел, где каждый узел это объект со своим набором свойств, атрибутов и внешних связей? Дерево отдельно, объекты отдельно или как-то еще?
                          +1
                          В каждом конкретном случае ответ свой — слишком мало информации.

                          Задаем себе вопрос — какие данные мне нужно будет читать/изменять атомарно? Ну и вот опираясь на это решаем, все хранить в документе, либо выносить полезную нагрузку в отдельную коллекцию.
                            0
                            Система документооборота, для сравнения можно взять файловую структуру, но более продвинутую: есть множество папок и файлов с произвольной вложенностью. Файлы имеют произвольный набор атрибутов, разный тип, по разному отображаются и редактируются. Папки больше походят на умные контейнеры, могут ограничивать типы входящих файлов, позволяют выполнять групповые операции над внутренними объектами, обеспечивают необходимое представление содержимого. Можно сделать ссылку как на папку, так и на файл. Изменения происходят в 2 этапа: добавляем новый узел (папку/файл) в дерево, изменяем свойства/атрибуты выбранного узла. Файлы могут быть также связаны с другими файлами (через атрибуты), например: описание файла, проекции файла (преобразование в pdf, jpg и т.д.). И дерево большое (более 100 000 узлов) и атрибутов много (более 10 000 000) То есть явно требуются реляционные связи, как это решается в MongoDB?
                              0
                              Как только появляется «много произвольных атрибутов» то монго резко становится намного удобнее MS SQL.

                              1. Сходу, напрашивается сохранять всех предков в монго.

                              2. Насколько часто происходит перемещение объектов между папками? По сути — это единственная проблема, которую я сейчас вижу. Но мне кажется для ms sql это тоже была бы проблема.

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

                              Если хотите — могу проконсультировать в индивидуальном порядке.
                              0
                              id, parent_id, data — структура мало чем отличается от классики
                                +1
                                И как выбрать всех предков данного узла (а-ля breadcrumbs)? А как удалить всех детей данного узла вне зависимости от уровня (при удалении самого узла)? Классическая структура подходит только для простейших применений.
                              +1
                              Materialized path?
                                +2
                                Я задавал этот вопрос на конференции девелоперу Монги. Если вложенность планируется большая и вообще никак не ограничивается, то все-таки лучше для этого посмотреть в сторону графоориентированных БД: neo4j например.
                                  0
                                  У всего есть предел, в том числе в том, сколько технологий можно освоить профессионально одновременно.

                                  Судя по сайту, neo4j не предоставляет api для .net, так что надо будет искать что-то еще [более сырое]. Вполне возможно, лучше уж забивать графы монгой.
                                    0
                                    neo4j не предоставляет api для .net

                                    Там есть REST api.
                                +1
                                >> За одно единственное обращение к базе данных — поиск по id категории и SeoFreindlyUrl, которое занимает 0,0012s (!) я получаю:

                                С этим понятно, вопрос сколько времени займет выборка:
                                — выборка по тегу, платья
                                — красных платьев с ценой более 200, но менее 570 (или какие там характеристики не уникальные)
                                  0
                                  Можно глянуть большую категорию с 2445 товарами

                                  Тесты показали, что выборки по случайным свойствам товаров данной категории занимают порядка 0.2-0.4 секунды, что слишком долго для веб приложений. Для фильтров мы строим что-то похоже на индексы самостоятельно без средств монго, и укладываемся в 0.01.

                                  Сортировать данные более чем в 1000 строк монго не любит — так что в больших категориях сортировки по полям запрещены.
                                  Если уж сильно нужно, можно считать за 1й заход id + необходимую характеристику, отсортировать в C#, а потом уже считать порцию нужных данных по id
                                  +2
                                  информация о платежах у вас тоже в Mongo?
                                    0
                                    Платежей пока нет.

                                    Если вас беспокоит потеря данных — не верьте слухам о том, что монго не стабильна. Сама по себе она как камень. Единственное, чего она боится, это незапланированной перезагрузки питанием без корректного завершения процесса.
                                      +1
                                      и еще забываем про теугольник CAP
                                        +1
                                        Недавно был такой на тестовом сервере. Удаление mongod.lock и перезапуск с параметром --repair помог, потерь я не заметил.
                                          +3
                                          Сама по себе она как камень.

                                          Так может утверждать только тот, кто ни разу не открывал багтрекер. Практически в каждой версии исправляют критические баги, приводящие к потере данных, падению сервера, неверным результатам и т.д.
                                            –2
                                            Без сомнений, вы правы, но шанс с этим столкнуться в реальной жизни минимальный. С каждым новым обновлением уверенность в надежности системы растет, скорость выхода обновлений также радует.

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

                                            Но и насчет потери данных тоже не стоит забывать: в Mongo журналирование появилось в 1.7.5 (~1.5 года назад). В 32-битной версии по умолчанию вообще отключено. Без журнала её хоть сколько-то надежной считать просто нельзя.
                                            В то же время, журнал невозможно настроить на полностью синхронную запись (по умолчанию — интервал 100мс). Конечно, в большинстве случаев это приемлемо, но уже компромисс.
                                              0
                                              32-битная версия имеет много ограничений, легче вообще её не рассматривать.

                                              В то же время, журнал невозможно настроить на полностью синхронную запись (по умолчанию — интервал 100мс). Конечно, в большинстве случаев это приемлемо, но уже компромисс.


                                              Всё наоборот. Для каждого запроса можно синхронизировать журнал на диск, базу данных на диск, минимальное количество реплик, минимально количество датацентров и т.д. Никаких компромиссов.
                                                0
                                                и каждая синхронизация — это тормоз…
                                                бесплатный сыр… сами знаете где,
                                                компромисс на компромисе
                                                  +1
                                                  Да блин, там куча вариантов. Можно отправить запрос не дожидаясь подтверждения — быстрее некуда. Можно дождаться подтверждения, что сервер принял запрос и записал в память не синхронизируя ни журнал, ни базу — запишется само через определенный интервал.

                                                  Дело в том, что можно регулировать durability очень гибко в широких пределах и для каждого запроса. Так чтобы одновременно и быстро и надежно физически не может быть.
                                            +1
                                            у меня проект реализован в Монго, а вот платежи старый добрый Мускуль
                                            0
                                            Проверками целостности данных должна заниматься СУБД, а не клиентское приложение.
                                              +2
                                              БД должна исправлять ошибки программиста, которые приводят к потере целостности?
                                                +1
                                                Если мы работаем с EC, то предоставление приложению возможности разрешения конфликтов (в соответствии с предметной областью или моделью данных) является единственным правильным подходом.
                                                +2
                                                Как только понадобится делать апдейты нескольких документов одновременно или хранить хоть сколь-нибудь объемные связанные данные, mongodb будет «жать».
                                                «Работать с нецелостными данными в приложении» только звучит просто; на деле же оказывается, что это приносит немало проблем.
                                                  0
                                                  Не совсем ясны ваши опасения.
                                                  1) Всего размер базы у нас 18 гиг и маленькой ее никак не назовешь. Добиться аналогичной скорости работы проекта на ms sql было бы намного сложнее
                                                  2) Ну и зачем-то ж нам дан мозг, было интересно его напрячь для не тривиальных решений.
                                                    0
                                                    Не совсем понятно, почему вы полностью от SQL баз отказались в своем проекте. Мы сейчас используем SQL базу в интернет-магазине и собираемся mongo прикрутить для ряда задач. Очевидно, что хранить характеристики со значениями, отдельно для каждого товара в ней значительно удобнее, равно как и выборки товаров по значениям характеристик делать. Но древовидные структуры типа каталога товаров и критически важные данные — заказы, пользователи, цены, я бы оставил в SQL.
                                                      0
                                                      Мы наоборот, используем ms sql для ряда исключительных задач.

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

                                                      Я тоже переживал за категории в Монго — оказалось очень удобно, к примеру вот такую страницу в случае использования sql придется, наверно, кэшировать. Я не написал, но этот проект не использует OutputCaching вообще — все страницы, запросов бывает до 15 тысяч в час, рендерятся на лету.

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

                                                      Запрос 1 — найти категорию
                                                      запрос 2 — найти 44 товара

                                                      Не помню сколько в сумме, где-то на уровне 1/20 секунды.

                                                      Один из прошлых проектов с деревом в 100000 узлов на ms sql безбожно тормозил.
                                                  0
                                                  Для статистики: в таблице товаров на данный момент 154 тысячи записей; в среднем одна запись занимает 22KB; а размер таблицы — 4GB.


                                                  Не совсем понял, почему таблица весит 4 GB. Изображения хранятся в таблице?
                                                    0
                                                    Нет, изображения храняться как файлы, в базе хранится тоьлко путь к файлу. Основной размер дают:
                                                    — описания товаров (статья)
                                                    — массив ключевых слов после стэмминга для поиска
                                                    — свойства
                                                      0
                                                      А индексы сколько занимают?
                                                        0
                                                        0.5 GB
                                                        Индексов довольно много:
                                                        — id
                                                        — категории
                                                        — внешнему id (товары синхронизируются с 1C)
                                                        — цене
                                                        — ключевым словам для поиска
                                                        — SeoFriendlyUrl
                                                        — приоритет показа
                                                        — название
                                                          0
                                                          0.5Гб индексов — это на 4Гб или на 18Гб данных.
                                                            0
                                                            Это на таблицу товаров, 4GB
                                                    0
                                                    >Как организовать полнотекстовый поиск с релевантностью в mongodb?
                                                    через Сфинкс, а как же еще?
                                                      0
                                                      >Есть ли жизнь без group by?
                                                      несомненно!
                                                        +3
                                                        А как вы обошли проблему отсутвия блокировок/транзакций?
                                                          0
                                                          Такой же вопрос. Отсутствие транзакций делает монгу очень плохим решением для некоторых приложений. Да, можно вручную как-то их напрограммировать, но в резульате из этих костылей ничего хорошего не выйдет.
                                                            0
                                                            Причём непонятно, почему они не сделают транзакции (пусть и жутко медленные, делающие лок всей БД). Пусть лучше будет официальный путь, чем куча самописных велосипедов.
                                                            +1
                                                            Это вечный вопрос. Вообще, в работе с NoSQL бывает очень не хватает именно транзакций. Все круто, но нет транзакций, а нужно гарантированно обновить несколько документов. Этим пожертвовали в угоду производительности.

                                                            Многие NoSQL-решения (включая Mongo) гарантируют Eventual Consistency (целостность «в конечном итоге»), что требует особого подхода к архитектуре проекта, но иногда просто не хватает обычных классических транзакций, когда нужно «чтоб прям здесь, сейчас и наверняка». Один из камней преткновения NoSQL, заставляющих идти на чрезмерные хитрости.

                                                            Для мира .NET есть решения NoSQL с транзакциями вроде RavenDB (очень хорошее решение, к слову), но MongoDB побыстрее будет и не привязано к Windows и .NET, что является преимуществом при масштабировании.
                                                              0
                                                              Причём решение достаточно странное, у меня есть задачи, в которых транзакции жизненно необходимы, но использоваться они будут достаточно редко, чтобы это не сказывалось на производительности, даже в случае блокировки всей БД.
                                                                0
                                                                Давайте разберем пример операции, где дествительно, важно чтобы изменения нескольких объектов были сохранены именно одновременно, может что и придумаем :)
                                                                  0
                                                                  Легко:
                                                                  Два человека обмениваются деньгами
                                                                  user1.balance+=amount user2.balance-=amount user1.save user2.save
                                                                    0
                                                                    Извиняюсь, тег code почему-то не учёл переносы строк :(

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

                                                                      user1.balance+=amount user2.balance-=amount user1.save user2.save


                                                                      Тут как раз описан этот пример.
                                                                        +1
                                                                        Ключевая таблица — Transactions — туда пишем 1 запись с двумя (в монго можно и больше, главное чтобы сумма была 0) объектами:
                                                                        { Changes: [ { User: «User1», Amount: +X}, {User: «User2», Amount: +X } ] }

                                                                        Когда нам нужно достоверно знать количество денег на счету — находим все changes по user = myid и считаем сумму.

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

                                                                          Это же, кстати, помогает нивелировать ошибки округления до почти ничтожных.
                                                                +3
                                                                несомненно за скорость надо платить,
                                                                но как только кончается оперативка — начинаются тормоза ( на set, относительно мускуля конечно на insert)
                                                                очень уж много данные занимают место (у меня больше 60Gb на 0.5М Пользователей)
                                                                очень долго делаются бэкапы… делать бэкап перед выкладкой — это смертеподобно :)
                                                                  0
                                                                  Тормозов от количества оперативки не заметил. Сейчас mongod занимает в памяти 10G, при основной базе 14 + staging где-то столько же.

                                                                  А вот скорость выполнения как бакапов, так и восстановления базы дейстивтельно не радует и поднимает новые вопросы.
                                                                    +1
                                                                    Монго всегда будет занимать всю свободную память, потому что это просто файловый кэш ОС. Главное чтобы индексы вмещались в память.

                                                                    По поводу бекапов, мне кажется, что вы используете mongodump/mongorestore. Они подходят для работы с отдельными коллекциями, и, например, индексы не сохраняют. Восстановление из правильного бекапа — это просто копирование директории data. Бекап должен выглядеть так: заходим на вторичную реплику, переводим процесс в режим только для чтения, копируем файлы данных, снимаем блокировку. Тут главное чтобы не кончился oplog. Если делать снапшот файловой системы, то разблокировать можно сразу же.
                                                                      0
                                                                      а что делать — если индексов куча и все не вмещаются???
                                                                      как на счет БД в 60 Гб?
                                                                        0
                                                                        Так и сколько ж там индексов?
                                                                        Выделить сервер с 8GB (лучше, конечно 16GB) памяти не такая космическая задача на сегодня.
                                                                          0
                                                                          я разработчик, а не инвестор
                                                                          а инвестор говорит, что проект пока денег не заработал
                                                                          вот и удивляемся, почему тормозит на 1 или 2 Gb (виртуалка)
                                                                          виртуалка — это как временное решение,
                                                                          но нет ни чего более постоянного чем временное.
                                                                            0
                                                                            Тогда вам один путь — искать возможность уменьшить объем данных. Когда проект станет зарабатывать данных, скорее всего, станет еще больше.

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

                                                                            Ну и на всякий случай
                                                                            — убедиться, что количество запросов при каждой загрузке страницы o(1)
                                                                            — Можно посмотреть, здесь описываются детальная оптимизация запросов: derickrethans.nl/indexing-free-tags.html

                                                                              0
                                                                              >убедиться, что количество запросов при каждой загрузке страницы o(1)
                                                                              кол-во запросов: 1 get & 1 set на каждой стр, за исключением одной: стр 2 get & 1 set
                                                                              > у меня запросы в основном по первичному индекс: получить данные игрока, есть запросы (меньшая часть) по вторичному индексу: выбор списка друзей.
                                                                              Более подробно про архитектуру у меня написана статья в моем болге (сервер пока не работает, ссылку дам позже)
                                                                            0
                                                                            Например, столько
                                                                            mysql> SHOW TABLE STATUS like 'table_ra%';
                                                                            +------------------+--------+---------+------------+-----------+----------------+-------------+-----------------+--------------+
                                                                            | Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length |
                                                                            +------------------+--------+---------+------------+-----------+----------------+-------------+-----------------+--------------+
                                                                            | table_raw | InnoDB | 10 | Compact | 257569966 | 146 | 37714132992 | 0 | 61952704512 |
                                                                              0
                                                                              Так это ж mysql, статья то про монго, которую, как минимум, легко раскидать по разным серверам.

                                                                              В монго у вас будет другая база, другие запросы и другие индексы.
                                                                              Вообще, когда индексов больше данных, это как-то нездорово.
                                                                                0
                                                                                Это действительно нездорово :)
                                                                                Хотя случаи бывают разные.

                                                                                Но такое есть и живет.

                                                                                И я не сильно уверен, что горизонтальный шардинг и репликация в монго лучше чем в мускуле. Вот когда доведется попробовать, тогда я смогу что-то сказать более однозначно.
                                                                            0
                                                                            а что делать — если индексов куча и все не вмещаются???


                                                                            Ну конечно sharding. Это же основная идея почти всех NoSQL хранилищ — легкое горизонтальное масштабирования. У монго оно еще и автоматическое.

                                                                            как на счет БД в 60 Гб?

                                                                            Например, тут размер базы 10TB.
                                                                              +1
                                                                              >У монго оно еще и автоматическое.
                                                                              на HiLoad 2011 в докладе «Почему не надо использовать MongoDB» говорили, что оно работает не совсем так, как ожидается.
                                                                            0
                                                                            Спасибо за идею, попробуем
                                                                        0
                                                                        Такое пафосное начало про то что выборка даже по primary key это мол время, а потом и страницы не проходит как идет FindOneById(id), которые по сути работы отличается от выборки по первичному ключу примерно как Санта Клаус отличается от Дед Мороза.

                                                                        Дальше читать уже как-то и не так захватывающе.
                                                                          0
                                                                          В обычной не реляционной базе это была бы пачка запросов, а не 1:
                                                                          Запросить товар
                                                                          запросить картинки
                                                                          запросить видео
                                                                          запросить характеристики

                                                                          Особенно резко все ухудшается при необходимости показать список объектов, у каждого их которых есть подобъекты — lazy loading быстро портит сокрость выполнения
                                                                            0
                                                                            Монго здесь по сути используется только как кэш. Можно по желанию использовать для этого всё что угодно, хоть даже memcached, который умеет сохранять данные на диск.
                                                                            0
                                                                            Блин, как раз в обычной реляционной.

                                                                            PS: Тот абзац чуть поправил.
                                                                            0
                                                                            а вы не задумывались над возможностью использовать хранимые процедуры в качестве транзакций?
                                                                            В Монго есть аналог: встраиваемые функции
                                                                            db.system.js.save( { _id: «foo», value: function( x, y ){ return x + y; } } );

                                                                            я тут погуглил cookbook.mongodb.org/patterns/perform-two-phase-commits/
                                                                              0
                                                                              Задумывался, но для нас вопрос транзакций вообще не актуально.

                                                                              Функция это хорошо, но ведь админ по ошибке может вырубить свет как раз в момент ее выполнения. Я бы скорее завел таблицу операций, писал бы туда всю необходимую информацию в одну запись.
                                                                              Асинхронный процесс выгребает операции и обновляет связанные объекты — habrahabr.ru/post/149047/#comment_5040625
                                                                                0
                                                                                ссылка классная, так тоже можно работать.
                                                                                  0
                                                                                  db.system.js.save( { _id: «foo», value: function( x, y ){ return x + y; } } );

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

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

                                                                                Самое читаемое