MongoDb и память

doublemother

Есть ситуация: есть некий сервер с N гигабайт памяти. Есть база, которая в мускуле со всеми индексами весила K<N гигабайт, но мы решили попробовать завести монго, и теперь она весит M>N гигабайт.
Проблемы начались уже при заполнении базы — в какой-то момент выжралась вся память и коннекты, заполняющие базу, подропались. Ладно, у нас есть база, пусть и не со всеми записями. Которая жрёт всю память на машине. Если поискать по интернетам, то разработчики монго говорят, что "те, кто говорят, что монго жрёт память, это просто парни, которые не шарят в мемори менеджменте. Мы юзаем клёвый mmap, и система сама освобождает память, когда надо".
Я понимаю, что в теории всё круто. На практике это означает, что, например, крутится у меня в консоли в watch скрипт (ps|grep и в какой-то момент он умирает со словами типа "cannot fork".
Подропал коллекции, смотрю, база по-прежнему много места жрёт, делаю из монго-шелла db.repairDatabase. Память съелась ВСЯ. То есть, я не смог из соседнего запущенного шелла даже ls, ps, free, kill и т.п. сделать. Убил монго-шелл, ничего не изменилось. Памяти на хосте нет вообще, убить монго не могу. После того, как все шеллы разлогинил, памяти не прибавилось, шелл не запустить, на хост ssh сделать нельзя — жду теперь, чтобы админы машину ребутнули.
Кто с монго сталкивался, вы встречали такие проблемы, и если да, то как решали?
Другие какие-нибудь nosql-решения кто-нибудь может посоветовать? Основное, что предполагается делать — аналог sql-ного запроса:
SELECT a, b, c, rating * if(a=$VAR1, 1, 10) AS rating FROM tablename WHERE b = $VAR2 ORDER BY rating DESC LIMIT $VAR3

okis

А цель использовать nosql вообще какая? Чем mysql не устроил?
Монга, насколько я помню, хранит индексы в памяти целиком, стоит посмотреть, сколько они занимают по сравнению со всей памятью (db.mycollection.totalIndexSize хотя сомневаюсь, что много).
repairDatabase — это очень и очень медленно, помогает если у тебя было много вспомогательных коллекций и записей, которые ты потом подропал.
Что говорит db.serverStatus.mem ?

Dasar

1 SELECT a, b, c, rating * if(a=$VAR1, 1, 10) AS rating FROM tablename WHERE b = $VAR2 ORDER BY rating DESC LIMIT $VAR3
для такого запроса скорее нужна материализованная вьюха (или таблица-кэш, которая руками обновляется, при изменении основной таблицы чем nosql

doublemother

Цель — под специально подготовленный кэш. У мускуля уже дают о себе знать накладные запросы на разбор запроса, плюс для него приходится извращаться с разбиением оного кэша на X таблиц, потому что иначе на больших размерах таблиц мускуль уже начинает тормозить.
Данные по серверу не покажу, потому что уже базу дропнул)
Впрочем, судя по всему, виной всему является то, что сервер оказался последней выжившей виртуалкой на OpenVZ, будь оно неладно. Буду переносить на нормальный сервер и смотреть.

okis

Почему не используешь redis/memcached?

doublemother

для такого запроса скорее нужна материализованная вьюха (или таблица-кэш, которая руками обновляется, при изменении основной таблицы чем nosql
Вот вся идея в том, что это УЖЕ и есть специальная таблица-кэш. Поле b ($VAR1) является ключом кэша, но оно может давать вплоть до 2к результатов. Мне надо, соответственно, только около 15 «самых релевантных». Чтобы не гонять все 2к результатов из мускуля на клиент, я и модифицирую rating (a=$VAR2 с последующей сортировкой.
Мне вот кажется, что это в принципе больше соответствует идее nosql. Но пока хочу изучить, будет ли выигрыш в производительности.

doublemother

Почему не используешь redis/memcached?
Потому что у мемкэшеда придётся всю сортировку и лимиты переносить на клиент (см. ответ 'у а редис — потому что посмотрел обзоры nosql и решил сначала попробовать монго. Ну и, у редиса, насколько я понимаю, опять-таки придётся часть функционала переносить на клиент.

pilot

Мне вот кажется, что это в принципе больше соответствует идее nosql.
Можно пояснить для тупых?
Насколько я понимаю идею nosql — быстрым в nosql БД будет доступ к единичным объектам, коих может быть очень много.
В этой задачке, вроде Indexes in MongoDB are conceptually similar to those in RDBMSes like MySQL. You will want an index in MongoDB in the same sort of situations where you would have wanted an index in MySQL .
Т.е. непонятно чем принципиально NoSQL может быть быстрее — идея не помогает тут быстродействию (?)

doublemother

Идея в том, что мы по имеем KV-хранилище → выборка всегда идёт просто по ключу → нет никаких затрат на разбор запроса. Мы базе ключ, она нам значения. Никакой компиляции запроса, связей между таблицами и ничего подобного.

Dasar

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

kirin

O_o. Поясните

doublemother

Я тоже не очень понял. Половина nosql-решений вообще вроде же не умеют "джоинов", нет?

pilot

Идея в том, что мы по имеем KV-хранилище → выборка всегда идёт просто по ключу → нет никаких затрат на разбор запроса.
Где тут "выборка по ключу"?
WHERE b = $VAR2 ORDER BY rating DESC LIMIT $VAR3

Dasar

возьмем произвольную структуру данных один ко многим:
например,
user
  name <name>
  phone <phone1>, mobile
  phone <phone2>, home
  ..
phone <phoneN-1>, work
  phone <phoneN>, work
чтобы хранить такую структуру в реляционной-базе, необходимо, как минимум две таблицы: user и phone.
и при получении такого юзера из базы появляется join, что достаточно накладно, если, например, стоит задача выдернуть 100 "произвольных" пользователей целиком со всеми их телефонами (или хотя бы первыми тремя)
nosql базы позволяют ограничиться одной "таблицей", в которой юзер хранится целиком, как одно "значение".
соответственно, при запросе из такой базы - join уже не нужен, он автоматически заменился на прямые ссылки, и производительность вырастает.
зы
ms sql и oracle, кстати, позволяют тоже обойтись одной таблицей, если перейти на частичное хранение данных в виде xml-я.

Dasar

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

pilot

и при получении такого юзера из базы появляется join, что достаточно накладно, если, например, стоит задача выдернуть 100 "произвольных" пользователей целиком со всеми их телефонами (или хотя бы первыми тремя)
view тут чем не годится?

Dasar

view тут чем не годится?
расшифруй.
интересует, что возвращает вью (какая схема данных а во-вторых, куда денется join?

pilot

интересует, что возвращает вью (какая схема данных а во-вторых, куда денется join?
А в чем проблема во view с join'ами ?

Dasar

А в чем проблема во view с join'ами ?
ты сейчас говоришь про то, что между кодом и субд можно сделать один запрос (сделав вью или процедуру) - это очевидная оптимизация.
но эта оптимизация от самого join-а не избавляется, а тормозит именно он, особенно если не удалось таблицы целиком в память поднять.
это связано с тем, что если для самих 100 "произвольных" юзеров можно добиться с помощью индексов, чтобы они лежали последовательно (в одном или смежных секторах диска то телефоны ста таких юзеров, уже будут раскиданы по куче секторов, если таблица телефонов большая.
а подъем ста разбросанных секторов с винта - это уже очень долгая операция, головки передвигаются не очень быстро.
зы
даже если винт заменяется на SSD или на память, то всё ускоряется, но все равно остается верным утверждение:
выборка последовательных записей на порядок-два быстрее, чем выборка разнесенных далеко находящихся друг от друга записей.

pilot

но эта оптимизация от самого join-а не избавляется, а тормозит именно он, особенно если не удалось таблицы целиком в память поднять.
Кагбы виден намек почему МонгоДБ память-то выел, не?
http://wiki.postgresql.org/wiki/Materialized_Views — есть способы заниматься этим в реляционной БД. Повторюсь, опять же, что NoSQL этой проблемы никаким магическим способом не решает, проблема остается.
Решать ее проще в реляционной БД (вроде потому как для выборок и работы с массивами данных NoSQL не предназначен, а тут после where как раз такое безобразие и идет.

pilot

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

Dasar

http://wiki.postgresql.org/wiki/Materialized_Views — есть способы заниматься этим в реляционной БД.
ок.
есть схема данных:
user
  name <name>
  phone <phone1>, <kind>
  ..
  phone <phoneN>, <kind>
  age <age>
необходимо обеспечить быстрое выполнение запросов под paging с сортировкой по имени при фильтрации по возрасту, по каждому юзеру выводятся name, age и первых три телефона (с приоритизацией сначала мобильный, потом рабочий, потом домашний)
в ооп-нотации - это будет что-то типа:
users
  .Where(user => user.age >= min-age && user.age <= min-age)
  .OrderBy(user => user.name)
  .Select(user => new User(name=user.name, phones=user.phones.OrderBy(phone => phone.kind-priority).Take(3 age=user.age
  .Skip(page-number * page-count)
  .Take(page-count)
как под эту задачу будет выглядеть материализованный вью?

Dasar

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

doublemother

Где тут "выборка по ключу"?


WHERE b = $VAR2 ORDER BY rating DESC LIMIT $VAR3
b — ключ. Выбираем по ключу. Дальше мы сортируем уже результат. Что не так?

kirin

возьмем произвольную структуру данных один ко многим:
например,
user
  name <name>
  phone <phone1>, mobile
  phone <phone2>, home
  ..
А если не нормализовать таблицу то join не нужен. тогда непонятно преимущество nosql

pilot

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

pilot

как под эту задачу будет выглядеть материализованный вью?
name, age, tel1, tel2, tel3
Дальше нужно посмотреть какие индексы лучше работают. Ты поясни какая магия в МонгоДБ эту ситуацию обработает лучше — там примерно такая же логика работы будет, только менее продвинутая, поскольку до постгреса ей пилить и пилить.

Dasar

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

Dasar

Ты поясни какая магия в МонгоДБ эту ситуацию обработает лучше
структура иерархического хранения данных

Dasar

name, age, tel1, tel2, tel3
а переворачивать как будешь телефоны из записей в колонки? при условии, что там поле телефона все-таки не одно, а их там несколько штук

pilot

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

Dasar

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

pilot

а переворачивать как будешь телефоны из записей в колонки?
Не понимаю я вашего языка :( Чего надо делать?

pilot

для начала ответь, чем иерархический индекс отличается от индекса в реляционной базе.
ничем
Я так и не понял, у тебя в монге мильен объектов с теми же свойствами name, age, tel1, tel2, tel3 . Как она по ним заметно быстрее искать будет чем постгрес? Напиши плз.

val63


у тебя в монге мильен объектов с теми же свойствами name, age, tel1, tel2, tel3
Это ты такую гениальную структуру собираешься в монге делать?

Dasar

ничем
по ссылке - не иерархический индекс.
по ссылке хранение данных, имеющих иерархические отношения, поверх плоского индекса.

pilot

О чем в итоге спор?
1. Опиши как работает МонгоДБ на данной задаче и с какими объектами и за счет чего ожидается прирост скорости. Имхо там не будет ничего такого что не реализуется на постгресе с примерно такими же затратами, если не лучше.
2. Ничего не нашел про иерархические индексы в МонгоДБ, они там те же B-tree, как и в Постгресе. Дай ссылку плз. В постгресе есть индексы для работы с иерархиями тем не менее.

Dasar

hint: btree-телефонов данного юзера можно вложить внутрь записи юзера, которая находится внутри btree-юзеров.
это и будет иерархический индекс.

pilot

hint: btree-телефонов данного юзера можно вложить внутрь записи юзера, которая находится внутри btree-юзеров.
Спасибо, капитан. Ты решение задачи опиши сначала. :smirk:

Dasar

Спасибо, капитан. Ты решение задачи опиши сначала. :smirk:
оно очевидно, если перечитать hint

pilot

оно очевидно, если перечитать hint
Перечитай и осознай что, очевидно, на постгресе задачка решается проще.
Оставить комментарий
Имя или ник:
Комментарий: