Tarantool 3.4
Дата выпуска: 14 апреля 2024 г.
Релизы на GitHub: 3.4.0
В версии Tarantool 3.4 добавлены следующие важные возможности и улучшения для редакций Community и Enterprise:
- Community Edition (CE)
- Междвижковые транзакции для memtx и vinyl.
- Новая функция
index:quantile()для поиска квантильного ключа в индексированном диапазоне данных. - Функциональные индексы в менеджере транзакций MVCC.
- Vinyl теперь поддерживает итераторы
np(следующий префикс) иpp(предыдущий префикс). - Исправлены некорректные сравнения чисел и повторы в уникальных индексах.
- Привилегии времени выполнения для
lua_callтеперь предоставляются перед вызовом функцииbox.cfg(). - Функции обратного вызова
stopдля ролей теперь вызываются во время плавного завершения работы (в порядке, обратном запуску ролей). - С помощью новых методов
has_role,is_routerиis_storageв модулеconfigможно проверять, включена ли конкретная роль для экземпляра. - Профилировщики LuaJIT стали более удобны в использовании.
- Встроенный сервис журналирования теперь кодирует аргументы таблицы в формате JSON.
- Исправлены многочисленные недочеты, найденные в MVCC, vinyl, WAL и создании моментальных снимков.
- Исправлена проблема с выделением избыточного объема памяти для
рабочих нагрузок, требующих использования
cdata.
- Enterprise Edition (EE)
- Новый движок для работы с колоночными данными в памяти:
memcs. - Новая стратегия начальной загрузки при аварийном переключении:
native. - Новый общедоступный API для доступа к удаленным кластерам
config.storageв качестве хранилища ключей и значений. - Двухэтапный процесс назначения, позволяющий избежать некорректного поведения координатора аварийного переключения.
- Новый движок для работы с колоночными данными в памяти:
Движок memcs хранит данные в формате memtx, но, в отличие от
memtx, он хранит данные в виде колонок, а не кортежей.
Каждому форматируемому полю присваивается своя собственная древовидная структура BPS (вектор BPS), в которой хранятся значения только этого поля. Если тип поля помещается в 8 байт, то необработанные значения полей сохраняются непосредственно в листьях дерева, без всякой кодировки. Для значений размером более 8 байт, таких как decimal, uuid или строки, в листьях хранятся указатели на данные, закодированные в формате MsgPack.
Основным преимуществом такой организации данных является значительное
повышение производительности при последовательном сканировании
колоночных данных по сравнению с memtx благодаря хранению данных рядом
с кэшом процессора. По этой причине memcs использует специальный C API
для такого колоночного сканирования: см. box_index_arrow_stream() и
box_raw_read_view_arrow_stream().
Максимальная производительность достигается при сканировании встроенных
типов полей. Как и memtx, memcs поддерживает запрос полных кортежей,
но его производительность здесь ниже, чем у memtx, поскольку кортеж
должен быть создан во время выполнения на основе значений отдельных
полей, собранных из каждого дерева колонок.
Прочие функции memcs: * Поиск по точкам. * Стабильные итераторы. *
Вставка / замена / удаление / обновление данных. * Пакетная вставка в
формате Apache Arrow. * Транзакции, в том числе междвижковые транзакции
с memtx (для последнего требуется указывать параметр
memtx_use_mvcc_engine = false). * Чтение данных из представлений
(views). * Вторичные индексы с возможностью указания закрытых колонок
и последовательного сканирования индексированных + закрытых колонок.
К встроенным типам полей относятся только типы с фиксированной длиной:
- Целочисленные: (u)int8/16/32/64. * С плавающей точкой: float32/64.
К типам полей с внешним хранилищем относятся: * Строки. * Все остальные типы, поддерживаемые Tarantool: UUID, Decimal, Datetime и т.д.
По умолчанию значения NULL сохраняются явным образом и занимают столько же места, сколько и любое другое допустимое значение колонки (1, 2, 4 или 8 байт в зависимости от конкретного типа поля). Также поддерживается RLE-кодировка значений NULL.
Для сравнения, RLE-кодирование колонки, содержащего 90% равномерно распределенных нулевых значений, снижает потребление памяти для такого колонки примерно в 5 раз.
Теперь Tarantool поддерживает инструкции для memtx и vinyl, заданные
в рамках одной транзакции, например:
local memtx = box.schema.space.create('memtx', {engine = 'memtx'})memtx:create_index('primary')local vinyl = box.schema.space.create('vinyl', {engine = 'vinyl'})vinyl:create_index('primary')memtx:insert({1, 'a'})vinyl:insert({2, 'b'})box.begin()memtx:replace(vinyl:get(2))vinyl:replace(memtx:get(1))box.commit()
Контролируемый координатор аварийного переключения теперь поддерживает
три стратегии начальной загрузки: native, supervised, auto.
Новая стратегия native налагает меньше ограничений, чем стратегия
auto. Также они отличаются внутренней реализацией (native
реализована на базе стратегии supervised). В остальном стратегия
native работает аналогично стратегии auto.
Стратегия native помогает решить следующие две проблемы: * Избежать
ошибки
Some replica set members were not specified in box.cfg.replication в
следующих случаях: * несколько реплик подключаются одновременно, *
набор реплик включает в себя неанонимные экземпляры CDC, * _cluster
содержит старые, ненужные реплики. * Заставить СУБД производить
начальную загрузку по команде координатора, не позволяя экземплярам
производить начальную загрузку самостоятельно.
Стратегия native рекомендуется для высокодинамичных кластеров с
автоматическим масштабированием, а также в большинстве других случаев.
Чтобы включить стратегию начальной загрузки native, укажите ее в
разделе replication в конфигурации кластера вместе с соответствующей
стратегией аварийного переключения (для стратегии native можно выбрать
любую стратегию аварийного переключения, например supervised):
replication:failover: supervisedbootstrap_strategy: native
Теперь можно предоставлять привилегии на выполнение Lua-функций с
помощью декларативной конфигурации, даже если база данных находится в
режиме "только для чтения"" или имеет устаревшую версию схемы. Также
можно разрешить пользователю guest вызывать Lua-функции перед
начальной загрузкой.
Можно указать права доступа к функциям, используя опцию lua_call в
конфигурации, например:
credentials:users:alice:privileges:- permissions: [execute]lua_call: [my_func]
Здесь пользователю alice дается разрешение на выполнение Lua-функции
my_func независимо от режима или статуса базы данных. Также
поддерживается специальная опция lua_call: [all], предоставляющая
доступ ко всем глобальным Lua-функциям, кроме встроенных, в обход
ограничений базы данных. Привилегии по-прежнему будут записываться в
базу данных, когда это возможно, чтобы сохранить совместимость с другими
типами привилегий.
В модуле config теперь доступны три новых метода: *
config:has_role('myrole') сообщает, назначена ли роль myrole для
текущего экземпляра, а config:has_role('myrole', {instance = 'i-001'})
делает то же самое для указанного экземпляра (i-001). *
config:is_router() сообщает, является ли текущий экземпляр
маршрутизатором vshard, а функция
config:is_router({instance = 'i-002'}) делает то же самое для
указанного экземпляра (i-002). * config:is_storage() сообщает,
является ли текущий экземпляр хранилищем vshard, а
config:is_storage({instance = 'i-003'}) делает то же самое для
указанного экземпляра (i-003).
К удаленным кластерам config.storage теперь можно получить доступ с
помощью метода config.storage_client.connect(endpoints[, {options}]).
Возвращаемый объект представляет собой соединение с удаленным хранилищем
значений key-value, доступ к которому осуществляется с помощью методов
:get(), :put(), :info(), :txn() с той же сигнатурой, что и в
серверном API config.storage.
В API config.storage_client также есть несколько особых методов:
:is_connected(), :watch(), :reconnect(), :close().
Вот несколько примеров использования:
-- Подключение к кластеру 'config.storage' с использованием конечных точек-- (endpoints) настроен в разделе 'config.storage'.---- Конечные точки можно указать в виде Lua-таблицы:---- local endpoints = {-- {-- uri = '127.0.0.1:4401',-- login = 'sampleuser',-- password = '123456',-- }-- }local endpoints = config:get('config.storage.endpoints')local client = config.storage_client.connect(endpoints)-- Передать значение подключенному клиенту.client:put('/v', 'a')-- Получить все сохраненные значения.local values = client:get('/')-- Очистить хранилище.local response = client:delete('/')-- Следить за ключевыми изменениями.local log = require('log')local w = client:watch('/config/main', function()log.info('config has been updated')end)-- Отменить регистрацию наблюдателя.w:unregister()