Top.Mail.Ru
Хранение данных с помощью memtx | Tarantool
Движки базы данных / Хранение данных с помощью memtx
Tarantool
Узнайте содержание релиза 2.8
Движки базы данных / Хранение данных с помощью memtx

Хранение данных с помощью memtx

Хранение данных с помощью memtx

Движок базы данных memtx используется в Tarantool по умолчанию. Он хранит все данные в оперативной памяти (RAM), поэтому значение задержки чтения у него очень низкое.

Очевидный вопрос: если все данные хранятся в памяти, как можно предотвратить их потерю в случае чрезвычайной ситуации, например при отключении электропитания или сбое экземпляра Tarantool?

Прежде всего, Tarantool сохраняет все изменения данных, записывая запросы в журнал упреждающей записи (WAL), хранящийся на диске. Подробнее это описано в разделе Персистентность данных. В случае распределенного приложения возможна синхронная репликация, которая обеспечивают согласованность данных в кворуме реплик. Хотя репликация напрямую не относится к механизму хранения, она отчасти способствует безопасности данных. Подробности можно найти в разделе Репликация данных.

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

Есть фиксированное количество независимых потоков выполнения. У этих потоков нет общего состояния. Вместо этого они обмениваются данными через очереди сообщений с низкими накладными расходами. Хотя такой подход ограничивает количество ядер, которое может использовать экземпляр, он устраняет конкуренцию за шину памяти и обеспечивает максимальную масштабируемость доступа к памяти и пропускной способности сети.

Обращаться к базе данных может только поток обработчика транзакций (далее — поток TX). В каждом экземпляре Tarantool есть только один такой поток. Транзакции в этом потоке выполняются строго последовательно. Транзакции, состоящие из нескольких инструкций, обеспечивают изоляцию: каждая транзакция видит согласованное состояние базы данных и применяет коммит со всеми своими изменениями атомарно. Во время коммита происходит передача управления, и все изменения транзакции записываются в WAL-файл одним пакетом. Если во время выполнения транзакции произошли ошибки, она полностью отменяется. Подробности можно найти в следующих разделах: Транзакции, Менеджер транзакций.

Внутри потока TX есть область памяти, в которой Tarantool хранит данные. Эта область называется Arena.

../../../../_images/arena2.svg

Данные хранятся в спейсах. Спейсы содержат записи базы данных — кортежи. Чтобы обращаться к данным, хранящимся в спейсах и кортежах, и изменять их, Tarantool создаёт индексы.

Распределением памяти для спейсов, кортежей и индексов внутри области Arena управляют специальные аллокаторы. Для хранения кортежей главным образом используется аллокатор slab. В Tarantool встроен модуль под названием box.slab, предоставляющий статистику распределения slab. С помощью этой статистики можно отслеживать общее использование памяти и ее фрагментацию. Подробности см. в :doc:` руководстве </reference/reference_lua/box_slab>` по модулю box.slab.

../../../../_images/spaces_indexes.svg

Внутри потока TX также есть цикл событий. Этот цикл содержит несколько файберов — кооперативных примитивов, позволяющих взаимодействовать со спейсами, то есть читать и записывать данные. Файберы могут обращаться к циклу событий и друг к другу как напрямую, так и посредством специальных примитивов, называемых каналами. Благодаря использованию файберов и кооперативной многозадачности движок memtx, как правило, свободен от блокировок.

../../../../_images/fibers-channels.svg

Чтобы взаимодействовать с внешними пользователями, используется отдельный сетевой поток, называемый также поток iproto. Поток iproto получает запрос из сети, разбирает и проверяет инструкцию из него, а затем преобразует ее в специальную структуру — сообщение, содержащее исполнимую инструкцию с параметрами. Затем iproto доставляет это сообщение в поток TX и исполняет запрос пользователя в отдельном файбере.

../../../../_images/iproto.svg

Чтобы обеспечить персистентность данных, Tarantool выполняет следующие действия.

  • Исполнив в памяти запросы на изменение данных, Tarantool записывает все эти запросы в файлы журнала упреждающей записи (WAL) (с расширением .xlog), хранящиеся на диске. Это делается в отдельном потоке, называемом поток WAL.
../../../../_images/wal.svg
  • Tarantool периодически делает снимок всей базы данных и сохраняет его на диск. Это необходимо для ускорения перезапуска экземпляра, так как если файлов WAL слишком много, то Tarantool не сможет быстро перезапуститься.

    Специальный файбер под названием демон снимков (snapshot daemon) позволяет сохранять снимки. Он читает консистентное содержимое всей области Arena и записывает его на диск в файл снимка (с расширением .snap). Из-за кооперативной многозадачности Tarantool не может записывать данные непосредственно на диск, так как это блокирующая операция. Поэтому Tarantool взаимодействует с диском через отдельный пул потоков из библиотеки fio.

../../../../_images/snapshot03.svg

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

Что происходит при перезапуске:

  1. Tarantool находит и читает последний файл снимка.
  2. Tarantool также находит и читает все файлы WAL, созданные после этого снимка.
  3. Как только снимок и файлы WAL будут прочитаны, набор данных в памяти будет полностью восстановлен. Он будет соответствовать состоянию экземпляра Tarantool на момент, когда тот прекратил работу.
  4. Во время чтения снимка и файлов WAL Tarantool строит первичные индексы.
  5. Когда все данные снова в памяти, Tarantool строит вторичные индексы.
  6. Tarantool запускает приложение.

Чтобы обращаться к данным, хранящимся в оперативной памяти, и работать с ними, Tarantool строит индексы, которые хранятся внутри области памяти Arena.

Tarantool поддерживает несколько типов индексов: TREE, HASH, BITSET, RTREE. Все они предназначены для разных сценариев использования.

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

Подробности про индексы можно найти на странице Индексы.

Хотя эта тема не имеет прямого отношения к движку memtx, она дополняет общую картину того, как работает Tarantool, когда приложение распределенное.

Репликация позволяет нескольким экземплярам Tarantool работать с копиями одной и той же базы данных. Эти копии остаются синхронизированными благодаря тому, что каждый экземпляр может сообщать другим экземплярам о совершенных им изменениях. Для этого используется WAL-репликация.

Чтобы отправить данные на реплику, Tarantool запускает еще один поток, называемый relay. Этот поток читает файлы WAL и отправляет их репликам. На каждой реплике выполняется файбер под названием applier. Он получает изменения от удаленного узла и применяет их к области Arena реплики. Все изменения записываются в файлы WAL через поток WAL реплики так же, как если бы они были сделаны локально.

../../../../_images/replica-xlogs.svg

В Tarantool репликация по умолчанию асинхронна: то, что транзакция проходит коммит локально на главном узле, не означает, что она отправляется на какие-то другие реплики.

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

Более подробные сведения вы найдете в главе о репликации.

Вот главные принципы, по которым работает движок:

  • Все данные находятся в оперативной памяти.
  • Доступ к данным производится только из одного потока.
  • Tarantool записывает все изменения данных в файлы WAL.
  • Периодически создаются снимки данных.
  • Для доступа к данным создаются индексы.
  • Файлы WAL можно реплицировать.