2014-02-05 4 views
2

Я пытаюсь создать систему, которая хранит данные, связанные с временем, для большого количества уникальных устройств (> 200 000) каждые 10 секунд или около того. Основная структура документа выглядит следующим образом:Mongo update large documents

{ 
    _id: ObjectID('$some_mongo_id'), 
    start: $start_epoch, 
    end: $end_epoch 
    identifier: $some_string, 
    values: { 
     'cpu': [ 
      [1, 2, 3, 4, ...], 
      [1, 2, 3, 4, ...] 
     ] 
    } 
} 

Несколько деталей, вероятно, не очень хорошо объяснены выше:

  • Мы предварительное выделение полноты каждого массива значений с нулевыми значениями в обойти любые проблемы с добавлением/перемещением. Я считаю, что это подтверждается, потому что dds stats paddingFactor всегда что-то вроде 1.000000000029.

  • Массив значений является многомерным, основанным на чтении и наблюдении, что массив больше похож на связанный список внутри mongo, поэтому это уменьшает количество прогулок, которые необходимо выполнить для данного обновления. Структура довольно произвольная, но для простоты воображения это в основном индекс 1 - час, индекс 2 - квартал, индекс 3 - минута.

  • Мы обновляем документы каждые 10 секунд и с помощью позиционных запросов обновления помещаем новое значение в нужное место в массиве. Что-то вроде «$ set: {'values.cpu.2.7': 1234}". Каждое обновление запрашивает только один документ на основе его уникального идентификатора + время начала/окончания (индексируется и проверяется на основе объяснения).

Мы видим значительно отличающуюся производительность в зависимости от того, насколько велик документ. Если документ охватывает один день, наша пропускная способность равна X и ограничена дисковым IO. Если длина документа составляет около часа, наша пропускная способность составляет около 8X и ограничена процессором (блокировка коллекции, наблюдаемая mongostat). Все остальные переменные остаются неизменными в этих тестах.

Я нашел this thread, который находится около 2 лет назад и, похоже, соответствует тому, что мы видим, но я не смог найти что-нибудь более недавнее, и у меня закончилось google fu. затем

Мой вопрос:

  • Когда Монго обновляет документ, это делает грязные все страницы, пролеты документа и, следовательно, требуют ОС, чтобы смыть все эти противы только страниц, что изменение произошло на? Кажется, так, но я не могу подтвердить официально.

  • Есть ли лучший способ структурировать/сделать это, чтобы выше не сжигать нас? Использование 1-часовых документов возможно, но это около 24x индексное пространство дневных документов, которое в этом случае довольно велико.

Заранее благодарим за любую помощь.

Технические биты:

сервер MongoDB 2.4.7 RHEL6 x86_64 питон 2.6.6 PyMongo 2.5.2-3

+1

Попытайтесь взглянуть на http://blog.mongodb.org/post/65517193370/schema-design-for-time-series-data-in-mongodb – Martin

+0

Отлично читайте Martin – Jinxcat

+0

Martin - Спасибо за эту ссылку, отлично читать. Как ни странно, мы фактически делаем почти то же самое! Кроме того, мы пытаемся использовать более крупные документы, чтобы уменьшить размер индекса. Я добавлю комментарий, спрашивая об этом. – Shazz

ответ

0

Что касается первой части вопроса, я действительно не имеют ответ я могу дать и быть на 100% уверенным. Я буду копать в него больше и вернуться к вам. Возможно, стоит и копать исходный код.

Что касается второй части, не уверен, что это будет точный ответ, но я надеюсь, что мои мысли по этому вопросу помогут вам.

Первое, что я заметил, что вы можете сэкономить место (и сделать документы немного меньше) на сокращенные названия:

{ 
    _id: ObjectID('$some_mongo_id'), 
    s: $start_epoch, 
    e: $end_epoch 
    i: $some_string, 
    v: { 
     'cpu': [ 
      [1, 2, 3, 4, ...], 
      [1, 2, 3, 4, ...] 
     ] 
    } 
} 

Если вы можете, сокращайте «CPU» на «C» тоже, и так далее , Не уверен, что у вас есть много свободы, хотя, в зависимости от ... именных столкновений. Причина, по которой я предлагаю это, должна быть очевидна, поскольку каждый сохраненный документ хранит эту строку в нем. Все дело в небольших данных.

Между двумя вариантами я бы выбрал 8X-производительность и был связан процессором.

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

Оптимальное использование меньших документов кажется лучшим вариантом на другом фронте; если вам нужно оплатить стоимость перемещения документа, вы оставите меньшие отверстия, и вам нужно найти пустое пространство меньшего размера.

Однако, я считаю, что многие другие обновления (коэффициент 24?) Вызывают намного больший объем обработки с каждым набором данных (найти документ, заблокировать, обновить, написать, (+ флеш?)). В промежутке между ними может быть «sweetspot» производительности, где диски io и cpu прекрасно танцуют вместе. Стоит проверить, что, если у вас есть роскошь. Если это неверно, и 8X действительно лучшее, что вы можете получить, тогда вам, возможно, придется начать принимать то, что вы, вероятно, попали в пределы того, что может предпринять одна машина.

Если процессор является узким местом, мое предложение заключается в обновлении решения для использования shards. Комбинация «Идентификатор» и «Старт», по-видимому, является хорошим кандидатом для ключа осколка. (Имейте в виду, что как только вы выберете свой ключ осколка, вы НЕ можете его изменить). Фактически, это даст вам несколько систем, которые могут выполнять запись в распределенной форме по документам. Это даст вам много пространства для дыхания ermm ... косвенно, но это также может увеличить ваши хосты по экспоненте.

+0

Jinxcat - спасибо за советы по сокращению имен полей. Это то, что мы планируем взглянуть, как только мы придем к схеме и API. Мы пробовали очертания, и производительность определенно возрастает, хотя соотношение производительности остается с теми же узкими местами. – Shazz