Масштабируемость сегментирования MongoDB — производительность запросов, обрабатывающих один фрагмент?

#mongodb #sharding

#mongodb #сегментирование

Вопрос:

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

Некоторые подробности:

Для моего простого теста я использовал две машины для сегментирования и пробовал запросы к аналогичным коллекциям с 2 миллионами строк и 7 миллионами строк. Очевидно, что это очень маленькие коллекции, которые даже не требуют сегментирования, но я был удивлен, увидев значительное постоянное замедление для запросов, обрабатывающих только один фрагмент. Запросы включали ключ сегментирования, были для наборов результатов от 10 до 100000 строк, и я измерил общее время, необходимое для прокрутки всех наборов результатов. И еще одно: поскольку моему приложению на самом деле потребуется гораздо больше данных, чем может поместиться в ОЗУ, все запросы были рассчитаны на основе холодного кэша.

Есть идеи, почему это может быть? Кто-нибудь еще наблюдал те же или противоречивые результаты?


Дополнительные подробности (по запросу Тео):

Для этого теста строки были небольшими (5 столбцов, включая _id), и ключ был основан не на _id, а на многозначном текстовом столбце, который почти всегда появляется в запросах.

Команда db.printShardingStatus() показывает, сколько существует фрагментов, а также точные значения ключей, используемые для разделения диапазонов для фрагментов. Средний блок содержит более 100 000 строк для этого набора данных, и проверка разделения значений ключа проверяет, что тестовые запросы попадают в один блок.

Для целей этого теста я измерял только чтение. Не было вставок или обновлений.


Обновить:

После некоторых дополнительных исследований, я полагаю, я определил причину замедления: блоки MongoDB являются чисто логическими, и данные в них физически НЕ расположены вместе (источник: «Масштабирование MongoDB» Кристины Ходоров). Это отличается от разделения в традиционных базах данных, таких как Oracle и MySQL. Это кажется существенным ограничением, поскольку сегментирование будет масштабироваться по горизонтали с добавлением сегментов / машин, но менее эффективно в вертикальном измерении, поскольку данные добавляются в коллекцию с фиксированным количеством сегментов.

Если я правильно понимаю, если у меня есть 1 коллекция с миллиардом строк, распределенных по 10 сегментам / машинам, даже запрос, который попадает только на один сегмент / машину, все равно запрашивает из большой коллекции из 100 миллионов строк. Если значения для ключа сегментирования находятся рядом на диске, то это может быть нормально. Но если нет, и я извлекаю более нескольких строк (например, 1000), то это, вероятно, приведет к множеству проблем ввода-вывода.

Итак, мой новый вопрос: почему бы не организовать фрагменты в MongoDB физически, чтобы обеспечить как вертикальную, так и горизонтальную масштабируемость?

Ответ №1:

Что заставляет вас говорить, что запросы касались только одного фрагмента? Если результат варьировался до 100 000 строк, это звучит маловероятно. Максимальный размер фрагмента составляет 64 Мб, и если ваши объекты не крошечные, многие из них не поместятся. Mongo, скорее всего, разделил ваши фрагменты и распределил их.

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

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

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

Запускайте mongostat во время выполнения тестов, это может вам многое рассказать (запустите mongostat --discover | grep -v SEC , чтобы увидеть показатели для всех ваших мастеров сегментов, не забудьте включить --port , если ваш mongos не запущен на 27017).


Решение вопросов в вашем обновлении: было бы действительно неплохо, если бы Mongo физически объединял фрагменты, но это не так. Одна из причин заключается в том, что сегментирование является слоем поверх mongod и mongod не полностью осознает, что это сегмент. Это серверы конфигурации и mongos процессы, которые знают о ключах сегментов и о том, какие фрагменты существуют. Следовательно, в текущей архитектуре mongod даже нет информации, которая потребовалась бы для хранения фрагментов вместе на диске. Проблема еще глубже: формат диска Mongo не очень продвинутый. Он по-прежнему (начиная с версии 2.0) не имеет онлайн-сжатия (хотя в версии 2.0 уплотнение улучшилось), он не может сжимать фрагментированную базу данных и по-прежнему обслуживать запросы. К сожалению, Mongo предстоит пройти долгий путь, прежде чем он сможет выполнить то, что вы предлагаете.

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

Ответ №2:

Отказ от ответственности: я работаю в Tokutek

Итак, мой новый вопрос: почему бы не организовать фрагменты в MongoDB физически, чтобы обеспечить как вертикальную, так и горизонтальную масштабируемость?

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