Сейчас на сервере (2хE5-2630, 128Гб RAM, SAS) стоит MongoDB 2.4.1
В ней две коллекции (в разных бд):
— Коллекция-1: 70 млн. записей (120 insert/s, 60 find/s, база с индексами ~ 9 Гб).
— Коллекция-2: 40 млн. записей (50 insert/s, 40 find/s, база с индексами ~ 11 Гб).
Цифры вроде не большие для данного железа. Вообще-то, запросов на чтение приходит на порядок больше, но по остальным информация берется из кэша (Redis). До монго доходит только в случае кэш промаха.
Проблема в том, что постоянно несколько операций find выполняются по 180 — 600 мс. Судя по отчетам профайлера и логам они ожидают, пока не освободится writing lock. Sun Apr 14 13:40:44.859 [conn3581] query db1.coll1 query: { _id: "14638g27189a6a957c6a792151df31b7" } ntoreturn:1 idhack:1 keyUpdates:0 locks(micros) r:188697 reslen:105 188ms
К базе вообще делаю только findOne или insert. Объем данных в insert не превышает 120 байт.
Вопрос: что делать? В дальнейшем объем данных вырастет до 500 — 1000 млн записей. И количество обращений на чтение до 10 тыс/сек.
Мне нужна БД с очень низкой латентностью для чтения по ключу. Никаких сложных выборок. Нужен backend для кэша. А монго со своим per-database write lock все портит.
Еще вариант, читать только со slave ноды. А писать на master. Но боюсь столкнуться с задержками при репликации данных, и, как следствие, с неконсистентными данными.
Что посоветуете? HBase, Hypertable? Нужно уложиться в максимум 2-5 мс при чтении из БД.
Потому что 1 миллиард ключей — это уже 166 гигабайт. Вполне нормально для сервера с 256Гб.
Но если по каждому ключу еще и данные хранить, то уже не впишемся по объему. У нас максимум 512Гб можно установить на мать.
Можно, конечно, делать user-level sharding для redis или использовать memcached. Думаем теперь и над этим.
С другой стороны, весь миллиард хранить в памяти не надо совсем. Из него активных — 100 млн. максимум. А остальное все же хотелось бы хранить в бд. И если вдруг потребуется — быстро вычитать и положить в кэш.
Возможно, нам стоит перейти на другой тип БД? Нам нужна отложенная запись (только insert) и быстрое (не более 2 мс) чтение. SSD готовы поставить, лишь бы помогло.
Ведь insert делается сначала в кэш. И все ноды забирают данные из кэша. Так что не особо важно, через сколько БД запишет данные.
А вот минимальная задержка при кэш промахе очень важна.
Да, я предполагал, что это само собой не будет один инстанс redis. Sharding подходящее решение.
Что у вас за диски стоят на сервере? Не думали перейти на ssd?
Диски SAS 15k RPM (какие именно, без понятия). 4 диска в RAID10. Raid аппаратный, 3ware 9750.
О SSD думали. Тестили. Как-то вообще не заметили выигрыша для монго.
Самое интересное, что диск особо-то и не занят.
Total DISK READ: 0.00 B/s | Total DISK WRITE: 157.69 K/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 19037 be/4 mongodb 0.00 B/s 703.82 K/s 0.00 % 4.55 % mongod --config /etc/mongodb.conf
Думаете, на одном сервере от нее будет толк?
На сколько я знаю, кассандра хорошо масштабируется в кластере. Но у нас и один сервер-то не загружен нормально.
Глобальная проблема опарий щаписи в том что каждая вставка заставляет перестраивать индексы.
Поэтому единстенная возможно решить проблему кардинально — это бить на части базу(шардинг), что приводит к тому что опареции записи распределяются за все шарды (желательно развномеррно, зависит от алгоритма выбора ключей) и как результат:
количество_записей_на_1_ноду = общее_количество_записей/количество_нод
Тоесть для 10000к в секунду и 100 нод — 10000/100 = 100 операйций записи в секунду.
Как бы других путей маштабирования записи — нет.
opium — правильно предложил, самый простой вариант шардинг внутри самой монги (это приведет к блокировке только части)
Cassadra / Riak возможно были бы более подходящими, но все опять же кластерные решения: больше нод — выше производительность.
Ну и в качестве странности: жить на одном сервере — с пробелмами записи не получится.
Шардинг внутри монги не особо помогает. Ключи нормально распределены, поэтому блокируется, конечно, меньше. Но все равно, блокировки есть.
Никто не спорит, что при увеличении количества инсертов надо будет делать шардинг.
Но то, что при 120 insert/s я уже не могу получить доступ на чтение к данным, которые целиком находятся в оперативной памяти, — это за гранью моего понимания.
Как есть.
Еще можно съемулировать отложеную запись. Тоесть вставлять новые данные во временную колекцию и раз в 1-5-15 минут переность в остновную.
Соответсвенно выборки будут выглядеть как:
выборка из большой базы + выборка ново вставленных.
Т.к. размер коллекции с новыми данными << меньше основной базы. Что привете к сщественному росту проиводительности чтения (также можно не использовать индексы для операция поиска)
Вот так и сделал сейчас. Чтение из кэша. А при промахе — из основной БД. Запись — в отдельную бд. Раз в час — миграция данных.
Но, мне кажется, это костыль.
Монга не прячет от тебя внутренее устройство.
Sphinx с дельта индексами делает тоже самое, просто логика спрятана.
Cassandra && Riak вытявают за счет нод.
Чудес не бывает.
При таком железе, почему бы не использовать MySQL или Postgre c секционированием данных блоками по 1М-10М, сделав ID инкрементарный BIGINT первичным ключом и поле данных, фиксированного размера(fixed), тогда поиск будет сводиться по сути к выбору нужной секции по iD и выбору нужной записи по формуле id*row_len. Это будет работать очень быстро даже с диска при условии, что файлы таблицы не будет фрагментированы физически на диске, ну а если из памяти не думаю что будет чем то уступать Mongo. Но естественно надо тестить
Постоянные коннекты тут будут обязательны я думаю.
Лично мне MongoDB всегда казалась костыльным решением. Красивый API, достаточно возможностей. Но вот как доходит дело до эксплуатации, постоянно вылазит куча недоработок. Знакомые отзывались, что и админить геморрой.
Лучше уж Riak + Redis, когда много нод нужно, ну и соотвественно имеете все плюсы и минусы dynamo-style хранилища.
Зато эти требования довольно строгие. Необходимо, чтобы все запросы на выборку данных по ключу укладывались… ну хоть в 10мс. А лучше в 1-3мс. Если не укладываются — срабатывает внешний таймаут.
Задержка между нодами 0.1 мс, так что с сетью проблем нет.
Сервер один — это пока он один. Мы не можем оценить, сколько и каких нам потребуется серверов, так как на довольно мощном железе столкнулись с проблемами на «детских» нагрузках.
Я не понимаю, почему монго заставляет мои операции выборки ждать освобождения write lock, если: 1) я сделал insert и выбираю точно не эту запись; 2) Вся бд и индексы легко помещается в памяти.
Если она так иногда подтормаживает, когда памяти больше, чем надо, то что будет, когда размер БД превысит размер RAM? 10-20 секунд на некоторые операции?
А я просто не первый раз слышу о проблемах, подобных вашим, поэтому на MongoDB смотрю скептически еще с первого знакомства, когда при выборе горизонтально масшатибируемого NoSQL решения она фейлилась на простых тестовых данных. Тогда были соотвествующие багрепорты, но вроде всё упиралось в архитектуру. И тоже как раз было связано с локами. Вообще решения, которые не могут гарантировать «предсказуемых результатов» при масштабировании трудно назвать ориентированными на highload.
Раз данные у вас так быстро растут, то может быть стоит обратить внимание на решения типа Riak или Voldemort?
На Riak тоже отзывы не очень позитивные. На средних базах он хорош. А когда число записей превышает 50 миллионов, уже начинается просадка по производительности.
Впрочем, это все с чужих слов. Сами не тестили.
Просадка будет в любом случае, но вот насколько при конкретном дизайне приложения — вопрос. Тестить нужно в любом случае. Кластер поднимается легко. Решение в любом случае за вами. Но несколько успешных историй перехода в частности с MongoDB на Riak я слышал. Но у них разная начинка, всё сильно зависит от архитектуры. В вашем случае, если я правильно понял, нужно persistent key-value store, таких много. У меня есть знакомые, которые вообще юзали leveldb напрямую, кстати, надо выяснить насколько успешно.
Может вам тогда запустить несколько нод монго на одном сервере и шардинг.
Не очень понятно что за локи у вас, по идее инсерт лочит только на запись, но не чтение.
По крайней мере так написано в документации. docs.mongodb.org/manual/faq/concurrency/
Сил сейчас нет развернуть по быстрому тестовую монгу чтобы проверить.
What type of locking does MongoDB use?
However, when a write lock exists, a single write operation holds the lock exclusively, and no other read or write operations may share the lock.
не знаю точно, почему тормоза в монго, но в мускуле ваша задача решается через бд с движком archive. На такой системе он спокойно переварит вашу нагрузку и даже под десяток виртуалок памяти останется. Вы сильно промахнулись с платформой, пошли за модой, теперь расплачивайтесь :)
Посмотрите на ElasticSearch, он хоть и позиционируется, в основном, как полнотектовый поисковик, прекрасно себя чуствует в роли NoSQL DB. Мы его уже так используем, очень довольны. Вот пример такого использования, хабра перевод. Особенно удобно то что для запросов в эластик используется JSON, после монго будет привычно (а еще и удобно)