В MongoDB стратегия максимизации производительности при записи в документы ежедневного журнала

#mongodb #io #nosql

#mongodb #io #nosql

Вопрос:

У нас есть коллекция данных журнала, где каждый документ в коллекции идентифицируется MAC-адресом и календарным днем. В основном:

 {
  _id: <generated>,
  mac: <string>,
  day: <date>,
  data: [ "value1", "value2" ]
}
  

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

Мы заметили, что ввод-вывод, измеряемый записанными байтами, увеличивается в течение всего дня, а затем снова падает в полночь по Гринвичу. Этого не должно происходить, потому что скорость сообщений журнала постоянна. Мы считаем, что неожиданное поведение связано с перемещением документов Mongo, в отличие от обновления их массивов журналов на месте. Для чего это стоит, stats() показывает, что коэффициент заполнения равен 1.0299999997858227.

Несколько вопросов:

  1. Есть ли способ подтвердить, обновляется ли Mongo на месте или перемещается? Мы видим некоторые изменения в журнале медленных запросов, но это похоже на неподтвержденные данные. Я знаю, что могу db.setProfilingLevel(2) , затем db.system.profile.find() и, наконец, искать "moved:true" , но я не уверен, можно ли это делать в загруженной производственной системе.
  2. Размер каждого документа очень предсказуемый и регулярный. Предполагая, что монго делает много ходов, каков наилучший способ выяснить, почему Монго не может более точно руководить? Или сделать Mongo presize более точным? Предполагая, что приведенное выше описание проблемы верно, настройка коэффициента заполнения, похоже, не сработает.
  3. Мне должно быть достаточно легко управлять документом и удалять любые догадки из Mongo. (Я знаю, что в документах по коэффициенту заполнения говорится, что я не должен этого делать, но мне просто нужно оставить эту проблему позади.) Каков наилучший способ создания документа? Кажется простым написать документ с полем массива мусорных байтов, а затем немедленно удалить это поле из документа, но есть ли какие-либо ошибки, о которых я должен знать? Например, я могу представить, что на сервере нужно дождаться операции записи (т. Е. Выполнить безопасную запись), прежде чем удалять поле мусора.
  4. Я был обеспокоен предварительным распределением всех документов дня примерно в одно и то же время, потому что кажется, что это насытит диск в то время. Является ли это обоснованной проблемой? Должен ли я попытаться распределить затраты на предварительное распределение по сравнению с предыдущим днем?

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

1. Скотт Эрнандес ответил на этот вопрос в группе Google, поэтому я публикую список к его ответу: groups.google.com/group/mongodb-user/browse_thread/thread /…

2. Последнее обновление: мы все еще пытаемся выяснить, что происходит.

Ответ №1:

Следующая комбинация, похоже, приводит к снижению производительности записи:

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

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

  1. Выключите ведение журнала. Вместо этого используйте больше реплик.
  2. Используйте документы меньшего размера. Обратите внимание, что размер документа здесь измеряется в байтах, а не в длине каких-либо массивов в документах.
  3. Журнал в отдельной файловой системе.

Кроме того, вот несколько других приемов, которые улучшают пропускную способность записи. За исключением сегментирования, мы обнаружили, что улучшения были постепенными, в то время как мы пытались решить проблему типа «это вообще не работает», но я включаю их здесь на случай, если вы ищете постепенные улучшения. Ребята из 10Gen провели некоторое тестирование и получили похожие результаты:

  1. Осколок.
  2. Разбейте длинные массивы на несколько массивов, чтобы ваша общая структура больше походила на вложенное дерево. Если вы используете час дня в качестве ключа, то документ ежедневного журнала становится:
    {"0":[...], "1":[...],...,"23":[...]} .
  3. Попробуйте предварительное распределение вручную. (Это нам не помогло. Дополнение Монго, похоже, работает так, как рекламируется. Мой первоначальный вопрос был ошибочным.)
  4. Попробуйте другие значения —syncdelay. (Это нам не помогло.)
  5. Попробуйте без безопасной записи. (Мы уже делали это для данных журнала, и во многих ситуациях это невозможно. Кроме того, это похоже на небольшой обман.)

Вы заметите, что я скопировал некоторые предложения из 10Gen здесь, просто для полноты картины. Надеюсь, я сделал это точно! Если они опубликуют пример кулинарной книги, я опубликую ссылку здесь.

Ответ №2:

mongodb попытается адаптивно упорядочить документы, поскольку узнает, как вы обновляете документы в течение определенного периода времени. Более подробную информацию можно найти наhttp://www.mongodb.org/display/DOCS/Padding Factor

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

В вашем случае кажется, что вы должны быть в состоянии сделать это, учитывая тот факт, что количество выборок в день постоянно (для вашего 5-минутного интервала.) Можете ли вы распечатать выходные данные из db.{yourcollectionname}.stats() ?

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

возможно, вам удастся обойти эту конкретную проблему, изучив другие схемы, но я не уверен, что все вы опробовали. Храните ли вы пары ключ-значение в массиве, где метка времени является ключом? примером модификации может быть переход к чему-то вроде: { id: 1, метрики: { «00:05″ : { » метрика1″ : «значение1»}, «00:10″ : { » metric2″ : «value2» } } }

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

1. Я знаю об адаптивной настройке, но если бы это работало, я не думаю, что мы увидели бы шаблон ввода-вывода, который я описал. Я добавлю статистику к вопросу. Да, я хотел бы вручную дополнить документ; смотрите Мой вопрос 3. Можете ли вы предоставить подробную информацию о том, как именно это сделать? Да, мы пробуем что-то, но, как я уже сказал, я ожидаю проблем, поэтому ответ от кого-то с опытом был бы более полезным. Я не думаю, что схема является ядром этой проблемы, поскольку каждая запись просто добавляет значение в конец поля массива, но я добавил пример к вопросу на всякий случай.

2. какой коэффициент заполнения mongodb рассчитал для вашей коллекции?

3. это в вопросе: 1.0299999997858227

Ответ №3:

Вы выполняете предсказуемое / постоянное количество нажатий в своем массиве данных. (24*60) / 5 = 288 за один день. Я бы настоятельно рекомендовал предварительно выделить массив из 288 элементов (или 1000 для гибкости и расширения, если вы решите делать это, например, каждые 3 минуты) в документе, а затем соответствующим образом обновлять документ для каждого добавления ввода данных. Вот как действовать :

-Добавьте еще 1 ключ к каждому документу, это сохранит номер ключа для обновления в ассоциативном data массиве. например. Изначально документ будет выглядеть так, как при первой вставке или обновлении массива данных с помощью update:

 {
      _id: <generated>,
      mac: <string>,
      day: <date>,
      data: { "1" : "myGarbageValue","2" : "myGarbageValue",
              "3" : "myGarbageValue"....."1000": "myGarbageValue" }
      n: 1
}
  

Для каждого обновления вы должны выполнить upsert для data ключа, равного n , и увеличить n
После 2 обновлений данных :

  {
          _id: <generated>,
          mac: <string>,
          day: <date>,
          data: { "1" : "myFirstValue","2" : "mySecondValue",
                  "3" : "myGarbageValue"....."1000": "myGarbageValue" }
          n: 3
    }
  

Плюсы :

  • Меньший рост документа, было бы лучше, если бы ваши myGarbageValue , myFirstValue mySecondValue были бы одинаковыми по размеру и формату.
  • n всегда сообщает вам текущий размер вашего data массива и позволяет запускать запросы диапазона для определения data размера массива, что было невозможно в вашей предыдущей структуре, поскольку оператор $size может возвращать только точное соответствие размера, а не диапазоны. http://www.mongodb.org/display/DOCS/Advanced Queries#AdvancedQueries-$size
  • Производительность Upsert выше, когда документ не расширяется. Здесь это upsert на основе чистого ключа, например, на data.23 , тогда как в старой структуре это был $push , который имеет линейную производительность вставки и становится медленнее по мере роста вашего data массива.

Минусы :

  • Ваши данные занимают больше места на диске, это не должно быть проблемой, поскольку вы обновляете свои данные каждые 24 часа.

Надеюсь, что эти предложения помогут. Попробуйте это и сообщите всем нам, если это принесет вам пользу.

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

1. Знаете ли вы официальный источник информации «push имеет линейную производительность вставки»? Я знаю об этом тесте blog.axant.it/archives/236 , но он утверждает только «вероятно». Мы попробуем предложить ассоциативный массив, но я был бы удивлен, если это сработает. Мы значительно ниже упомянутого порога в 5000 человек. Кроме того, я не могу придумать объяснения, почему алгоритм линейной вставки будет преобразовываться в физическое поведение ввода-вывода, которое мы видим, поскольку он не может перемещать каждую запись.

2. Привет, jtoberon, официально не задокументировано, но это было замечено во время некоторого сравнительного анализа. Однако для массива небольшого размера 288, подобного вашему, это не будет иметь большого значения. И вы правы, разница в вводе-выводе заключается не в различии алгоритмов вставки / обновления, а в том, что из-за предварительного выделения элементов в ассоциативном массиве ваш объект document не увеличивается. Следовательно, mongodb выполняет меньше операций, меньше ввода-вывода.

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