Tarantool 3.0
Дата выпуска: 26 декабря 2023 г.
Релизы на GitHub:
В релизе Tarantool 3.0 добавлен новый декларативный подход к конфигурации кластера, новый визуальный инструмент – Tarantool Cluster Manager, а также множество других новых возможностей и исправлений. В этом документе представлен обзор наиболее важных возможностей для редакций Community и Enterprise.
Начиная с версии 3.0 в Tarantool можно настраивать полную топологию кластера с помощью декларативной конфигурации в формате YAML вместо настройки каждого экземпляра с помощью отдельного Lua-скрипта. При новом подходе можно задавать локальную конфигурацию для каждого экземпляра в YAML-файле или хранить данные конфигурации в одном надежном месте, например, в кластере Tarantool или etcd.
В приведенном ниже примере показано, как может выглядеть конфигурация небольшого шардированного кластера. На схеме кластер состоит из 5 экземпляров: одного роутера и 4 хранилищ, которые образуют два набора реплик. Для каждого набора реплик мастер-экземпляр задается вручную.

В приведенном ниже примере показано, как топология такого кластера может выглядеть в файле конфигурации YAML:
groups:
Полный пример можно найти в репозитории документации на GitHub: sharded_cluster.
С помощью последней версии утилиты tt можно управлять экземплярами Tarantool, настроенными с помощью нового подхода. Запустить все экземпляры в кластере можно одной командой, а также проверить их статус или остановить их:
$ tt start sharded_cluster• Starting an instance [sharded_cluster:storage-a-001]...• Starting an instance [sharded_cluster:storage-a-002]...• Starting an instance [sharded_cluster:storage-b-001]...• Starting an instance [sharded_cluster:storage-b-002]...• Starting an instance [sharded_cluster:router-a-001]...
В Tarantool Enterprise Edition можно хранить данные конфигурации в одном
надежном месте, например, в кластере etcd. Для
этого нужно настроить параметры подключения в разделе config.etcd
файла конфигурации, например:
config:etcd:endpoints:- http://localhost:2379prefix: /myappusername: sampleuserpassword: '123456'http:request:timeout: 3
config:etcd:endpoints:- http://localhost:2379prefix: /myappusername: sampleuserpassword: '123456'
При использовании приведенной выше конфигурации экземпляр Tarantool ищет конфигурацию кластера по следующему пути:
http://localhost:2379/myapp/config/*
В Tarantool 3.0 Enterprise Edition добавлен новый визуальный инструмент – Tarantool Cluster Manager (TCM). TCM предоставляет веб-интерфейс для управления, настройки и мониторинга кластеров Tarantool EE, использующих централизованное хранилище конфигурации.

С помощью TCM можно управлять несколькими кластерами и решать широкий круг задач: от написания конфигурации кластера до интерактивного выполнения команд на конкретных экземплярах.

В TCM реализована система управления доступом на основе ролей, с помощью которой можно управлять доступом пользователей к кластерам, их конфигурациям и хранимым данным.

Встроенный настраиваемый механизм ведения журнала аудита и аутентификация LDAP делают TCM подходящим решением для различных корпоративных требований безопасности.

Начиная с версии 3.0 в Tarantool добавлена расширенная статистика потребления памяти для конкретного спейса или определенных кортежей.
Обычно для получения размера памяти, занимаемой указанным спейсом, используется метод space_object:bsize():
app:instance001> box.space.books:bsize()---- 70348673...
Помимо самих данных, спейсу требуется дополнительная память для хранения служебной информации. Общий объем используемой памяти можно посмотреть с помощью box.slab.info():
app:instance001> box.slab.info().items_used---- 75302024...
С помощью нового метода space_object:stat() можно определить, как используются дополнительные 5 Мб памяти:
app:instance001> box.space.books:stat()---- tuple:memtx:waste_size: 1744011data_size: 70348673header_size: 2154132field_map_size: 0malloc:waste_size: 0data_size: 0header_size: 0field_map_size: 0...
Этот отчет содержит следующую информацию:
header_sizeиfield_map_size: размер служебной информации.data_size: фактический размер данных, равныйspace_object:bsize().waste_size: объем памяти, теряемой из-за внутренней фрагментации в slab-аллокаторе.
Чтобы получить подобную информацию о конкретном кортеже, используйте tuple_object:info():
app:instance001> box.space.books:get('1853260622'):info()---- data_size: 277waste_size: 9arena: memtxfield_map_size: 0header_size: 10...
В новой версии добавлена возможность вручную выбрать лидера начальной загрузки для набора реплик. Лидер начальной загрузки – это узел, который создает начальный снимок и регистрирует все реплики в наборе реплик.
Сначала нужно задать для параметра
replication.bootstrap_strategy
значение config. Затем укажите лидера начальной загрузки с помощью
параметра <replicaset_name>.bootstrap_leader.
groups:group001:replicasets:replicaset001:replication:bootstrap_strategy: configbootstrap_leader: instance001instances:instance001:iproto:listen:- uri: '127.0.0.1:3301'instance002:iproto:listen:- uri: '127.0.0.1:3302'instance003:iproto:listen:- uri: '127.0.0.1:3303'
В версии 3.0 в Tarantool Enterprise Edition добавлен ряд новых возможностей, повышающих уровень безопасности в кластере:
-
Добавлен конфигурационный параметр
secure_erasing, который заставляет Tarantool несколько раз перезаписывать файл данных перед удалением, чтобы сделать восстановление удаленного файла невозможным. При новом подходе к конфигурации эту возможность можно включить следующим образом:security:secure_erasing: trueЭтот параметр также можно задать с помощью переменной окружения
TT_SECURITY_SECURE_ERASING. -
Добавлен параметр
auth_retries, задающий максимальное количество повторных попыток аутентификации перед включением троттлинга. Задать этот параметр можно следующим образом:security:auth_retries: 3 -
Добавлена возможность использовать новый SSL-сертификат с тем же именем путем перезагрузки конфигурации. Для этого используйте функцию
reload(), предоставляемую новым модулемconfig:app:instance001> require('config'):reload()---...
В Tarantool Enterprise Edition добавлены следующие новые возможности для журналирования аудита:
-
В каждую запись аудита добавлен уникальный идентификатор (UUID).
-
Добавлены уровни важности для записей аудита. Теперь каждому системному событию аудита присваивается уровень важности в зависимости от его значимости.
-
Добавлен параметр
audit_log.audit_spaces, который настраивает список спейсов, для которых события операций с данными должны записываться в журнал. -
Добавлен параметр
audit_log.audit_extract_key, который заставляет подсистему аудита записывать в журнал первичный ключ вместо полного кортежа при операциях DML. Это может быть полезно для уменьшения размера журнала аудита при работе с большими кортежами.
Пример конфигурации журнала аудита в версии 3.0 может выглядеть
следующим образом, включая новые параметры audit_spaces и
audit_extract_key:
audit_log:to: filefile: audit_tarantool.logfilter: [ddl,dml]spaces: [books]extract_key: true
При такой конфигурации запись аудита для операции DELETE может выглядеть следующим образом:
{"time": "2023-12-19T10:09:44.664+0000","uuid": "65901190-f8a6-45c1-b3a4-1a11cf5c7355","severity": "VERBOSE","remote": "unix/:(socket)","session_type": "console","module": "tarantool","user": "admin","type": "space_delete","tag": "","description": "Delete key ["0671623249"] from space books"}
Запись содержит новые поля uuid и severity. Последнее поле
description содержит только информацию о ключе удаленного кортежа.
Flight recorder, доступный в Enterprise
Edition, – это инструмент сбора событий, который собирает различную
информацию о работающем экземпляре Tarantool. В версии 3.0 можно
читать записи flight recorder с помощью API,
предоставляемого модулем flightrec.
Чтобы включить flight recorder в YAML-файле, задайте значение true для
параметра flightrec.enabled:
flightrec:enabled: true
Затем с помощью Lua API можно открывать и читать файлы *.ttfr:
app:instance001> flightrec = require('flightrec')---...app:instance001> flightrec_file = flightrec.open('var/lib/instance001/20231225T085435.ttfr')---...app:instance001> flightrec_file---- sections: &0requests:size: 10485760metrics:size: 368640logs:size: 10485760was_closed: falseversion: 0pid: 1350...app:instance001> for i, r in flightrec_file.sections.logs:pairs() do record = r; break end---...app:instance001> record---- level: INFOfiber_name: interactivefiber_id: 103cord_name: mainfile: ./src/box/flightrec.ctime: 2023-12-25 08:50:12.275message: 'Flight recorder: configuration has been done'line: 727...app:instance001> flightrec_file:close()---...
В этом релизе немного изменен подход к поставке Tarantool конечным пользователям в виде пакетов DEB и RPM. В предыдущих версиях Tarantool собирался для наиболее популярных дистрибутивов Linux и их последних версий.
Начиная с этого релиза, поставляются только два набора пакетов DEB и RPM. Отличие в том, что эти пакеты содержат статически скомпилированный бинарный файл Tarantool. Благодаря такому подходу пакеты DEB и RPM можно устанавливать на любые дистрибутивы Linux, основанные на CentOS и Debian.
Для обеспечения работы Tarantool на широком спектре различных дистрибутивов и их версий пакеты RPM и DEB готовятся на CentOS 7 с glibc 2.17.
В предыдущих версиях Tarantool уже поддерживался тип varbinary для
хранения данных. Однако для работы с
полями базы данных типа varbinary требовались обходные пути, например
использование C для обработки таких данных.
В версию 3.0 добавлен новый модуль varbinary для работы с объектами
varbinary. Этот модуль реализует следующие функции:
-
varbinary.new()– создает объект varbinary из обычной строки. -
varbinary.is()– возвращает true, если аргумент является объектом varbinary. В примере ниже объект создается из строки:
local varbinary = require('varbinary')local bin = varbinary.new('Hello world!')
Теперь встроенные декодеры по умолчанию декодируют поля с бинарными данными в объект varbinary:
local varbinary = require('varbinary')local msgpack = require('msgpack')varbinary.is(msgpack.decode('\xC4\x02\xFF\xFE'))--[[---- true...]]varbinary.is(yaml.decode('!!binary //4='))--[[---- true...]]
Это также означает, что данные, хранящиеся в базе данных с типом поля
varbinary, теперь возвращаются в Lua не как обычная строка, а как
объект varbinary.
Можно вернуться к старому поведению, переключив новый параметр
binary_data_decoding compat, так как это изменение
может нарушить обратную совместимость:
compat:binary_data_decoding: old
Теперь при определении формата спейса можно задавать
значения по умолчанию для конкретных полей. В этом
примере поля isbn и title имеют указанные значения по умолчанию:
box.schema.space.create('books')box.space.books:format({{ name = 'id', type = 'unsigned' },{ name = 'isbn', type = 'string', default = '9990000000000' },{ name = 'title', type = 'string', default = 'New awesome book' },{ name = 'year_of_publication', type = 'unsigned', default = 2023 }})box.space.books:create_index('primary', { parts = { 'isbn' } })
Если вставить кортеж с недостающими полями, будут подставлены значения по умолчанию:
app:instance001> box.space.books:insert({ 1000, nil, nil, nil })---- [1000, '9990000000000', 'New awesome book', 2023]...
Можно также задать пользовательскую логику для генерации значения по
умолчанию. Для этого создайте функцию с помощью
box.schema.func.create:
box.schema.func.create('current_year', {language = 'Lua',body = "function() return require('datetime').now().year end"})
Затем укажите имя функции в параметре default_func при определении
формата спейса:
box.space.books:format({-- ... --{ name = 'year_of_publication', type = 'unsigned', default_func = 'current_year' }})
Подробнее см. в index-defaults.
В версии 3.0 API для создания триггеров полностью
переработан. Добавлен новый модуль trigger, с помощью которого можно
задавать обработчики как для предопределенных, так и для
пользовательских событий.
Для создания триггера необходимо:
-
Указать имя события, с которым будет связан триггер.
-
Задать имя триггера.
-
Задать функцию-обработчик триггера. В примере ниже показано, как подписаться на изменения в спейсе
books:
local trigger = require('trigger')trigger.set('box.space.books.on_replace', -- имя события'some-custom-trigger', -- имя триггераfunction(...)-- обработчик триггераend)
В релизе 2.11 добавлены следующие возможности:
- Представления чтения – снимки в памяти всей базы данных, на которые не влияют последующие изменения данных.
- Пагинация для получения данных порциями.
В релизе 3.0 объект представления чтения поддерживает аргументы after и
fetch_pos для методов select и pairs:
-- Выбрать первые 3 кортежа и получить позицию последнего кортежа --app:instance001> result, position = read_view1.space.bands:select({}, { limit = 3, fetch_pos = true })---...app:instance001> result---- - [1, 'Roxette', 1986]- [2, 'Scorpions', 1965]- [3, 'Ace of Base', 1987]...app:instance001> position---- kQM...-- Затем эту позицию можно передать в качестве параметра 'after' --app:instance001> read_view1.space.bands:select({}, { limit = 3, after = position })---- - [4, 'The Beatles', 1960]- [5, 'Pink Floyd', 1965]- [6, 'The Rolling Stones', 1962]...
Начиная с версии 3.0 протокол IPROTO расширен поддержкой отправки имен полей кортежа в ответах IPROTO_CALL и других ответах IPROTO. Это упрощает разработку коннекторов Tarantool, а также работу с кортежами, полученными в результате удаленных вызовов процедур или от роутеров.
Вернуться к прежнему поведению можно, переключив параметр
box_tuple_extension модуля compat:
compat:box_tuple_extension: old
Начиная с версии 3.0 имена в SQL, например, имена
таблиц, колонок или ограничений, чувствительны к регистру. До версии
3.0 приведенный ниже запрос создавал таблицу MYTABLE:
CREATE TABLE MyTable (i INT PRIMARY KEY);
Чтобы создать таблицу MyTable, имя нужно было заключить в двойные
кавычки:
CREATE TABLE "MyTable" (i INT PRIMARY KEY);
Начиная с версии 3.0 имена чувствительны к регистру, и двойные кавычки больше не требуются:
CREATE TABLE MyTable (i INT PRIMARY KEY);
Для обратной совместимости в новой версии также поддерживается повторный
поиск по имени в верхнем регистре. Это означает, что приведенный ниже
запрос сначала пытается найти таблицу MyTable, а затем MYTABLE:
SELECT * FROM MyTable;
В релиз 3.0 включено исправление проблемы LuaJIT
gh-562, связанной с
невозможностью обработки внутренних ошибок компилятора при выполнении
трассировок с помощью pcall. Примеры таких ошибок:
-
Ошибка
Out of memoryможет возникать для запросовselect, возвращающих большой объем данных. -
Ошибка
Table overflowвозникает при превышении максимального количества ключей в таблице. Приведенный ниже скрипт пытается заполнить Lua-таблицу большим количеством ключей:
local function memory_payload()local t = {}for i = 1, 1e10 dot[ffi.new('uint64_t')] = iendendlocal res, err = pcall(memory_payload)print(res, err)
В предыдущей версии Tarantool с 32-битным Lua GC этот скрипт вызывает
следующую ошибку, несмотря на использование pcall:
PANIC: unprotected error in call to Lua API (not enough memory)
В Tarantool с 64-битным Lua GC этот скрипт вызывает ошибку
Table overflow:
PANIC: unprotected error in call to Lua API (table overflow)
Начиная с версии 3.0 эти ошибки обрабатываются корректно со следующими результатами:
false not enough memory -- 32-bit Lua GCfalse table overflow -- 64-bit Lua GC
В результате в Tarantool 3.0 повышается стабильность работы в случаях, когда пользовательские скрипты содержат ошибочный код.