Оптимальный способ создания документов mongo с учетом ttl и дискового ввода-вывода

Какова наилучшая стратегия использования индекса TTL в базе данных Mongo с учетом соотношения дискового ввода-вывода.

Предисловие:

Я работаю над кластерной инфраструктурой mongodb (v2.*), где каждый узел имеет около 1 ТБ жесткого диска. Там информация журнала сохраняется в течение 7 дней. По истечении этого времени они не нужны и должны быть удалены. Имеется 6 баз данных по 10 коллекций в каждой и более 10 миллионов документов в каждой коллекции. Предположим, что мы храним 100 ГБ временных данных каждый день.

Поэтому я создал простой индекс для поля createdAt.

  db.my_collection.ensureIndex( { "createdAt": 1 }, { expireAfterSeconds: 604800, background : true });

Это приведет к удалению всех документов, вставленных в эту коллекцию, через 7 дней после отметки времени, которая была помещена в createdAt. Это мне ясно. Но я не уверен, как создать документы, которые будут сохранены в коллекции.

В документах mongo для фоновых индексов указано:

The background task that removes expired documents runs every 60 seconds.

Вопрос:

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

например Вот 3 способа создания объектов для сохранения. Я использовал синтаксис php, но это не имеет значения.

Вариант 1:

   'createdAt' => new MongoDate(strtotime(date('Y-m-d')))

Здесь все документы, созданные сегодня, будут сохранены со временем создания, например. "2015-04-09 00:00:00". Это означает, что срок действия всех документов истекает "2015-04-16 00:00:00".

Плюсы:

  • Каждый день вскоре после полуночи использование диска должно уменьшаться на 100 ГБ.
  • Вы можете легко увидеть, если есть и ошибка. Если нет падения в diskusage, что-то пошло не так.

Минусы:

  • Удаление 100 ГБ данных приведет к огромным дисковым операциям ввода-вывода и, возможно, замедлению других процессов.
  • Документы сохраняются менее ровно 7 дней из-за недостающих часов и минут.

Вариант 2:

   'createdAt' => new MongoDate(strtotime(date('Y-m-d h:i:s')))

Здесь все созданные документы будут иметь разное время создания, например. "2015-04-09 13:23:45". Это означает, что срок действия этого образца документа истекает "2015-04-16 13:23:45".

Плюсы:

  • Документы хранятся ровно 7 дней.
  • Диск io будет почти постоянным в течение всего дня. Возможность вмешательства в другие процессы меньше.

Минусы:

  • Проверить, есть ли ошибка, не так просто, как вариант 1, так как документы будут удалены в течение дня. Не будет резкого скачка в использовании диска.

(Вариант 3):

Я думаю, что это должно быть то же самое, что и вариант 2. Тем не менее, я хотел упомянуть об этом здесь.

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

db.my_collection.ensureIndex( { "deleteAt": 1 }, { expireAfterSeconds: 0, background : true });

А затем создайте объект следующим образом:

'deleteAt' => new MongoDate(strtotime("+7 days")),

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


person cb0    schedule 09.04.2015    source источник


Ответы (1)


Отказ от ответственности: я ни в коем случае не являюсь разработчиком PHP, поэтому я не могу дать вам PHP-код.

Проблема здесь в том, что вы хотите удалить все данные в начале дня. Итак, когда задача TTL запускается в первый раз после 00:00, она пытается удалить все документы, как вы написали

Однако ваши предположения не совсем точны. Если запись в журнале была сделана сегодня в 16:00, точная дата истечения срока действия с недельным сроком хранения (604 800 секунд) будет четверг, 16 апреля 2015 г., 16:00.

Таким образом, самый простой способ распределить дисковый ввод-вывод на 1440 запусков фонового процесса TTL — использовать в качестве ориентира не только дату, но и время.

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

{
  _id: <SomeObjectId>,
  entry: "Something happened!"
  createdAt: ISODate("2015-04-02T09:11:27.038Z")
}

Вы сможете выбрать все соответствующие записи так же просто, как

db.logentries.find({createdAt:{$gt:ISODate("2015-04-03T00:00:00.000Z") } })

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

person Markus W Mahlberg    schedule 09.04.2015
comment
Большое спасибо, я не искал никакого php-кода. Просто некоторые мысли и идеи. То, что вы предлагаете, звучит хорошо и воодушевило меня на размышления. Я перейду на TTL, который включает минуты и секунды. - person cb0; 14.04.2015
comment
@cb0: Рад, что смог помочь! - person Markus W Mahlberg; 14.04.2015