Коллекция MongoDB используется для данных журнала: индекс или нет? - PullRequest
4 голосов
/ 09 февраля 2011

Я использую MongoDB в качестве временного хранилища журналов.Коллекция получает ~ 400 000 новых строк в час.Каждая строка содержит метку времени UNIX и строку JSON.

Периодически я хотел бы копировать содержимое коллекции в файл на S3, создавая файл для каждого часа, содержащий ~ 400 000 строк (например, today_10_11.log содержит все строки, полученные между 10:00 и 11:00).Мне нужно сделать эту копию, пока коллекция получает вставки.

Мой вопрос: как влияет на производительность индекс в столбце отметки времени для 400 000 часовых вставок в строках на дополнительное время, необходимое для запросаколичество строк в часах.

Рассматриваемое приложение использует написанный на Ruby, работающий на Heroku и использующий плагин MongoHQ.

Ответы [ 4 ]

4 голосов
/ 09 февраля 2011

Mongo индексирует поле _id по умолчанию, и ObjectId уже начинается с отметки времени, поэтому в основном Mongo уже индексирует вашу коллекцию по времени вставки для вас.Поэтому, если вы используете значения по умолчанию Mongo, вам не нужно индексировать второе поле метки времени (или даже добавлять его).

Чтобы получить время создания идентификатора объекта в ruby:

ruby-1.9.2-p136 :001 > id = BSON::ObjectId.new
 => BSON::ObjectId('4d5205ed0de0696c7b000001') 
ruby-1.9.2-p136 :002 > id.generation_time
 => 2011-02-09 03:11:41 UTC 

Чтобы сгенерировать идентификаторы объектов для заданного времени:

ruby-1.9.2-p136 :003 > past_id = BSON::ObjectId.from_time(1.week.ago)
 => BSON::ObjectId('4d48cb970000000000000000') 

Так, например, если вы хотите загрузить все документы, вставленные на прошлой неделе, вы просто ищете _idчем past_id и меньше чем id.Итак, с помощью драйвера Ruby:

collection.find({:_id => {:$gt => past_id, :$lt => id}}).to_a
 => #... a big array of hashes.

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

Дополнительная информация об идентификаторах объектов.

4 голосов
/ 09 февраля 2011

У меня есть приложение, подобное вашему, и в настоящее время оно имеет 150 миллионов записей журнала.При 400 КБ в час эта БД быстро разрастется.400 тыс. Вставок в час с индексацией по метке времени будут гораздо полезнее, чем выполнение неиндексированного запроса.У меня нет проблем с вставкой десятков миллионов записей в час с индексированной меткой времени, но если я делаю неиндексированный запрос на метке времени, это займет пару минут на сегменте из 4 серверов (с привязкой к процессору).Индексированный запрос появляется мгновенно.Так что определенно индексируйте его, накладные расходы на индексирование не так высоки, и 400 тыс. Записей в час не так уж много для монго.

Однако нужно обратить внимание на размер памяти.При 400 тысячах записей в час вы делаете 10 миллионов в день.Это будет занимать около 350 МБ памяти в день, чтобы сохранить этот индекс в памяти.Поэтому, если это займет некоторое время, ваш индекс может стать быстрее памяти.

Кроме того, если вы усекаете записи через некоторое время, используя команду remove, я обнаружил, что при удалении создается большое количество операций ввода-вывода на диск иэто связано с диском.

1 голос
/ 09 февраля 2011

Я бы просто использовал ограниченную коллекцию, неиндексированную, с пространством, скажем, 600 тыс. Строк, чтобы учесть слякоть. Раз в час сбрасывайте коллекцию в текстовый файл, а затем используйте grep, чтобы отфильтровать строки, которые не соответствуют заданной дате. Это не позволяет вам использовать полезные элементы БД, но означает, что вам не нужно беспокоиться об индексах коллекций, сбросах или любой другой ерунде. Критически важный для производительности бит удерживает коллекцию свободной для вставок, поэтому, если вы можете выполнить «жесткий» бит (фильтрация по дате) вне контекста БД, у вас не должно быть заметного влияния на производительность. 400-600k строк текста для grep тривиальны и, вероятно, не должны занимать больше секунды или двух.

Если вы не возражаете против слякоти в каждом журнале, вы можете просто скопировать и сжать коллекцию. В каждом дампе вы будете получать более старые данные, но если вы не вставите более 600 тыс. Строк между дампами, у вас должна быть непрерывная серия снимков журнала по 600 тыс. Строк в каждой.

1 голос
/ 09 февраля 2011

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

Подумайте о сохранении временной метки в поле _id вместо MongoDB ObjectId.Пока вы храните уникальные метки времени, все будет в порядке._id не должен быть ObjectID, но имеет автоматический индекс _id.Это может быть вашим лучшим выбором, поскольку вы не добавите дополнительную нагрузку на индекс.

...