Статьи

Хранение данных временных рядов с MongoDB и TokuMX

[Эта статья была написана Stephane Combaudon]

Хранение данных временных рядов является частой моделью для баз данных — будь то для журналов или для любого вида мониторинга. Такие данные имеют следующие свойства: записи вставляются, но также никогда не обновляются, скорость вставки может быть высокой и срок действия записей может истечь через некоторое время. MongoDB и  TokuMX  хорошо подходят благодаря гибкой схеме. Но как мы можем эффективно обработать срок действия данных? Доступно несколько вариантов: ограниченные коллекции, коллекции TTL и разбиение (только TokuMX), ​​но все они имеют различные функции и профили производительности.

Резюме

  • Ограниченные коллекции: очень хорошая производительность вставки, но не подходит для шардинга и трудно предсказать, когда истекает срок действия документов.
  • Коллекции TTL: дата истечения срока проста в применении и совместима с шардированием, но очистка или записи неэффективны.
  • Разбиение: очень хорошая производительность для вставок и продувки, но не совместимо с шардированием и доступно только с TokuMX.

Закрытые коллекции

Чтобы создать  app_stats ограниченную коллекцию  размером 1 ГБ, используйте следующую команду:

> db.createCollection( "app_stats", { capped: true, size: 1024*1024*1024 } )

MongoDB запишет в эти коллекции циклически: как только выделенные файлы заполнятся, данные в начале первого файла будут перезаписаны. Это очень хорошо, чтобы убедиться, что ваша коллекция никогда не превысит установленный вами размер. Однако предсказать размер, который вам потребуется для хранения данных за 6 месяцев, может быть непросто.

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

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

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

Коллекции TTL

TTL-коллекции  используют другой подход: они нормальные, но у них есть индекс, который имеет специальную опцию. Например:

> db.logs.createIndex({insertDate:1}, {expireAfterSeconds: 86400})

Этот индекс обеспечит автоматическое истечение срока действия записей через один день. Довольно аккуратно!

А поскольку коллекция TTL — это обычная коллекция, вы можете осколить ее, если вам нужно.

Однако основным ограничением является процесс очистки: каждую минуту фоновый поток будет искать документы, срок действия которых истек, и, если он найдет их, удалит их. На самом деле это ничем не отличается от приложения, выполняющего задание cron каждую минуту для удаления старых документов: оно добавляет рабочую нагрузку постоянной очистки, которая может отрицательно влиять на производительность вставки.

Обратите внимание, что индексы TTL не работают с ограниченными коллекциями.

Разметка (TokuMX)

С TokuMX вы можете  разделить  ваши данные, как вы бы с MySQL. Например, если вы хотите создать коллекцию, разделенную на  insertDate поле, вы должны использовать эти команды:

> db.createCollection('stats_part',{primaryKey:{insertDate:1,_id:1}, partitioned: true})
> db.stats_part.addPartition({insertDate:ISODate("2015-05-31T23:59:59")})
> db.stats_part.addPartition({insertDate:ISODate("2015-06-30T23:59:59")})
[...]

The main benefit of partitioning is that expiring data is extremely simple and fast: remove the corresponding partition(s) with the dropPartition() function. Another nice property is that you can be very flexible regarding how large your partitions can grow. This could deserve a whole blog post, but let me give a quick example.

Suppose you want to expire data after 6 months. With regular MongoDB, indexes are using B-Trees so insertion is only fast if indexes fit in memory. So if you could create a partitioned collection, insertions would only be fast if the partition you are writing to (the last one) would fit in memory. Then you would probably have to create a partition for every day. With TokuMX, there is no such limitation and insertion performance will be as good if you have larger partitions like one partition per week or one partition per month.

Any drawback of partitioning? It involves some application overhead as you need to write the logic to periodically drop old partitions and create new ones. And sharding is not supported.

Conclusion

There is no one-size-fits-all solution when it comes to storing time-series data in MongoDB and TokuMX, but several options with their own benefits and trade-offs. Note that if your collection needs to be sharded, a TTL index is the only option. And if you are using TokuMX, partitioning is something to look at if you were planning a capped collection.