Хранение данных с помощью memtx
Движок хранения memtx используется в Tarantool по умолчанию. Этот движок хранит все данные в оперативной памяти (RAM), за счет чего обеспечивается низкая задержка чтения.
В Tarantool предусмотрены следующие способы предотвращения потери данных в аварийных ситуациях, таких как сбой питания или отказ экземпляра Tarantool:
- Tarantool обеспечивает сохранность всех изменений данных, записывая запросы в журнал упреждающей записи (write-ahead log, WAL), который хранится на диске. Кроме того, Tarantool периодически создает снимок базы данных целиком и сохраняет его на диске. Подробнее см. в разделе Персистентность данных.
- В случае распределенного приложения для обеспечения согласованности данных на кворуме реплик используется синхронная репликация. Хотя репликация не относится напрямую к движку хранения, она является частью решения вопроса безопасности данных. Подробнее см. в разделе Репликация данных.
В этом разделе кратко рассмотрены следующие темы со ссылками на другие разделы, где они описаны более подробно.
Есть фиксированное количество независимых потоков выполнения. У этих потоков нет общего состояния. Вместо этого они обмениваются данными через очереди сообщений с низкими накладными расходами. Хотя такой подход ограничивает количество ядер, которое может использовать экземпляр, он устраняет конкуренцию за шину памяти и обеспечивает максимальную масштабируемость доступа к памяти и пропускной способности сети.
Только один поток, а именно поток обработки транзакций (далее поток TX), имеет доступ к базе данных, и для каждого экземпляра Tarantool существует только один поток TX. В этом потоке транзакции выполняются в строго последовательном порядке. Многооператорные транзакции существуют для обеспечения изоляции: каждая транзакция видит согласованное состояние базы данных и фиксирует все свои изменения атомарно. Во время фиксации происходит передача управления (yield), и все изменения транзакции записываются в WAL единым пакетом. В случае возникновения ошибок при выполнении транзакции она полностью откатывается. Подробнее см. в следующих разделах:
Внутри потока TX есть область памяти, в которой Tarantool хранит данные. Эта область называется Арена (Arena).
Данные хранятся в спейсах. Спейсы содержат записи базы данных – кортежи. Для доступа к данным, хранящимся в спейсах и кортежах, и управления ими Tarantool строит индексы.
Распределением памяти для спейсов, кортежей и индексов внутри области арены управляют специальные
аллокаторы. Для хранения кортежей главным образом используется аллокатор slab. В
Tarantool встроен модуль под названием box.slab, предоставляющий статистику распределения slab. С помощью этой статистики
можно отслеживать общее использование памяти и ее фрагментацию. Подробности см. в
руководстве по модулю box.slab.
Также внутри потока TX есть цикл событий. В цикле событий выполняется ряд файберов. Файберы представляют собой кооперативные примитивы, обеспечивающие взаимодействие со спейсами, то есть чтение и запись данных. Файберы могут взаимодействовать с циклом событий и друг с другом напрямую или с помощью специальных примитивов, называемых каналами. Благодаря использованию файберов и кооперативной многозадачности, движок memtx в типичных ситуациях работает без блокировок.
Чтобы взаимодействовать с внешними пользователями, используется отдельный сетевой поток, называемый также поток iproto. Поток iproto получает запрос из сети, разбирает и проверяет инструкцию из него, а затем преобразует ее в специальную структуру – сообщение, содержащее исполнимую инструкцию с параметрами. Затем iproto доставляет это сообщение в поток TX и исполняет запрос пользователя в отдельном файбере.
В Tarantool обеспечивается персистентность данных следующим образом:
- После выполнения запросов на изменение данных в памяти Tarantool записывает каждый такой запрос в файлы
журнала упреждающей записи
(
.xlog), которые хранятся на диске. Это происходит в отдельном потоке, называемом потоком WAL.
-
Tarantool периодически делает полный снимок базы данных и сохраняет его на диске. Это необходимо для ускорения перезапуска экземпляра, так как при большом количестве WAL-файлов Tarantool может долго перезапускаться.
Для сохранения снимка используется специальный файбер, называемый демоном снимков состояния. Он считывает согласованное содержимое всей области арены и записывает его на диск в файл снимка (
.snap). Из-за кооперативной многозадачности Tarantool не может писать напрямую на диск, так как это блокирующая операция. Именно поэтому Tarantool взаимодействует с диском через отдельный пул потоков из библиотеки fio.
Таким образом, при перезапуске Tarantool данные можно полностью восстановить даже в аварийных ситуациях, например при отключении питания или падении экземпляра Tarantool, когда хранящаяся в оперативной памяти база данных утеряна.
Что происходит при перезапуске:
- Tarantool находит последний файл снимка и считывает его.
- Tarantool находит все файлы WAL, созданные после этого снимка, и также считывает их.
- После считывания файлов снимка и WAL в памяти восстанавливается полный набор данных, соответствующий состоянию на момент остановки экземпляра Tarantool.
- Во время чтения файлов снимка и WAL Tarantool строит первичные индексы.
- Когда все данные снова оказываются в памяти, Tarantool строит вторичные индексы.
- Tarantool запускает приложение.
Чтобы обращаться к данным, хранящимся в оперативной памяти, и работать с ними, Tarantool строит индексы, которые хранятся внутри области памяти арены.
Tarantool поддерживает несколько типов индексов: TREE, HASH, BITSET, RTREE. Все они предназначены для разных сценариев использования.
Можно выполнять SELECT-запросы как по первичным, так и по вторичным ключам индекса. Ключи могут быть составными.
Подробнее об индексах см. раздел Индексы.
Хотя эта тема не имеет прямого отношения к движку memtx, она дополняет общую картину того, как работает Tarantool, когда приложение распределенное.
Репликация позволяет нескольким экземплярам Tarantool работать с копиями одной и той же базы данных. Эти копии остаются синхронизированными благодаря тому, что каждый экземпляр может сообщать другим экземплярам о совершенных им изменениях. Для этого используется WAL-репликация.
Чтобы отправить данные на реплику, Tarantool запускает еще один поток, называемый relay. Этот поток читает файлы WAL и отправляет их репликам. На каждой реплике выполняется файбер под названием applier. Он получает изменения от удаленного узла и применяет их к области арены реплики. Все изменения записываются в файлы WAL через поток WAL реплики так же, как если бы они были сделаны локально.
В Tarantool репликация по умолчанию асинхронна: то, что транзакция проходит коммит локально на главном узле, не означает, что она отправляется на какие-то другие реплики.
Эту проблему решает синхронная репликация. Каждая синхронная транзакция проходит коммит лишь после репликации на некотором количестве экземпляров, и только тогда клиенту приходит ответ о завершении транзакции.
Более подробные сведения вы найдете в главе о репликации.
Вот главные принципы, по которым работает движок:
- Все данные находятся в оперативной памяти.
- Доступ к данным осуществляется из одного потока.
- Tarantool записывает все запросы на изменение данных в WAL.
- Периодически создаются снимки данных.
- Для доступа к данным строятся индексы.
- WAL может реплицироваться.