Tarantool 2.11 LTS: Рассказываем про новые возможности администрирования и безопасности

Привет. Меня зовут Владимир Салыкин, я директор по продукту Tarantool. Мы выпустили Tarantool 2.11 LTS — стабильный релиз с долгим циклом поддержки. Работа над ним началась в мае 2022 года, и сейчас релиз включает в себя более тысячи коммитов от 42 авторов. Мы все много работали над решением основных проблем с обслуживанием и администрированием, с которыми ранее сталкивались наши пользователи. 

В этой статье мы хотим рассказать про ключевые фичи, которые были добавлены в релизе.

66ef1e6ac4789d735f5079b379cdb839.png

Community edition: улучшено администрирование и обслуживание

Добавлены автоматические прерыватели для предотвращения отключений из-за длинных запросов: ограничение времени выполнения файберов и явная директива SQL SEQSCAN. 

Ограничение времени выполнения файбера

Файбер — это набор инструкций (команд), которые выполняются по принципу кооперативной многозадачности. В Tarantool 2.11 добавлен механизм, который не позволяет файберам работать слишком долго без передачи управления с помощью yield. Каждому файберу теперь назначается временное окно — слайс выполнения. Это максимальный промежуток времени, в течение которого файбер может работать, не передавая управление другим файберам. 

Есть два вида слайсов — уровня Warning и Error:

  1. Если превышена длительность уровня Warning, в журнал заносится предупреждение, но файбер продолжает выполняться. 

  2. Если же превышена длительность Error, то любая функция, которая проверяет слайс файбера, вернет ошибку. 

tarantool> box.cfg{log_level = 'warn'}
---
...

tarantool> fiber, clock = require('fiber'), require('clock')
---
...

tarantool> fiber.set_max_slice{warn = 1.5, err = 10}
---
...

tarantool> t = clock.monotonic() 
while clock.monotonic() - t < 5 do box.space._space:select() 
end2023-02-20 14:18:16.527 [1105858] 
main/103/interactive fiber.h:1042 W> fiber has not yielded for more than 1.500 seconds 
(файбер не передавал управление более 1,500 секунд)
---
...

tarantool> fiber.set_max_slice{warn = 1.5, err = 2.5}
---

Явное последовательное сканирование в движке SQL

Tarantool в первую очередь предназначен для работы в режиме OLTP (Online Transaction Processing). Это означает, что объем чтения данных ожидается довольно небольшим. Однако в SQL легко пропустить неоптимальную формулировку и загрузить базу данных долгими запросами. Теперь можно убедиться, что запрос не приведет к полному последовательному сканированию таблицы.

Последовательное сканирование:

SELECT a FROM t;
SELECT a FROM t WHERE a + 1 > 10;

Поиск по индексу:

SELECT a FROM t where a > 9;

Добавлена новая настройка сессии sql_seq_scan для явного запрета на полное сканирование таблиц:

SET SESSION "sql_seq_scan" = false;
SELECT a FROM t WHERE a + 1 > 10;
-- Ошибка: Для 'T' не разрешено сканирование

Новое ключевое слово SEQSCAN разрешает сканирование таблиц:

SET SESSION "sql_seq_scan" = false;
SELECT a FROM SEQSCAN t WHERE a + 1 > 10;

Строгое ограничение в RAFT

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

Если включено ограничение election_fencing, это вынуждает лидера сложить свои полномочия при потере кворума соединений. Соединение считается потерянным, если оно неактивно (не отвечает) в течение времени, превышающего тайм-аут. Этот тайм-аут не задается напрямую, а вычисляется относительно replication_timeout.

Добавлен новый режим строгого ограничения. Он изменяет тайм-аут отключения для текущего лидера RAFT так, что его тайм-аут становится в два раза короче, чем для его реплик. Если предположить, что replication_timeout одинаков для каждой реплики в наборе, то это уменьшает вероятность того, что новый лидер может быть избран прежде, чем старый сложит свои полномочия.

Более подходящие значения по умолчанию для запуска и загрузки

По умолчанию реплика попытается подключиться ко всем мастерам или не запустится. Однако если указать replication_connect_quorum = N, где N означает число больше или равное нулю, это будет означать, что реплике нужно подключиться к N мастеров.

Изначально replication_connect_quorum был разработан для упрощения загрузки наборов реплик. Но на практике он добавляет немало сложностей и проблем в процессе эксплуатации и обслуживания кластера:

  • пользователи, которые не использовали этот параметр, сталкивались с проблемами с частичной загрузкой (Bootstrap) кластера;

  • пользователи, которые использовали этот параметр, испытывали проблемы при перезапуске экземпляра.

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

  1. При загрузке набора реплик узлы откажутся загружаться, пока в голосовании не будет достигнуто большинство, то есть, например, replication_connect_quorum = 3, если #box.cfg.replication равен 4 или 5, или replication_connect_quorum = 2, если #box.cfg.replication — 2 или 3. Более того, лидер не сможет загрузиться, если не увидит, что каждый подключенный узел выбрал его в качестве лидера загрузки.

  2. При присоединении новой реплики к существующему кластеру реплика не загрузится только в том случае, если она не смогла ни с кем соединиться. Если хотя бы одно соединение установлено, реплика будет пытаться присоединиться, как и раньше. Более того, реплика проверяет, что в ее таблице box.cfg.replication есть все зарегистрированные узлы кластера. Это гарантирует, что она пыталась подключиться ко всем и выбрала наилучшего лидера загрузки.

  3. При реконфигурации репликации на работающем экземпляре и восстановлении из локальных WAL-файлов реплика попытается подключиться ко всем узлам, указанным в box.cfg.replication. Любое количество соединений и даже их отсутствие будет считаться успешным, но реплика останется в режиме Orphan, пока не будет синхронизирована со всеми подключенными узлами.

Если вы хотите вернуться к старому поведению, у параметра bootstrap_strategy в box.cfg доступен режим Legacy. В этом режиме узел ведет себя точно так же, как и раньше: кворум для соединения и синхронизации определяется значением replication_connect_quorum и ни лидер загрузки, ни присоединяющиеся реплики не выполняют никаких дополнительных проверок.

Интерактивный отладчик Lua-кода 

Tarantool написан на языке С, но пользователь может работать с ним с помощью Lua. А если совсем точно, то с одной из его реализаций, LuaJIT — не с просто интерпретатором, а еще и с поддержкой JIT-компиляции. Ранее отлаживать исходники на Lua с помощью стандартных средств консоли Tarantool было очень сложно. Обычно все ограничивалось несколькими вызовами print в разных частях кода. В этом релизе мы добавили оболочку консольного отладчика, которая значительно упрощает отладку модулей Lua.

Отладчик Lua поддерживает все стандартные отладочные операции:  

  • пошаговое выполнение;  

  • проверку значений переменных в локальном или глобальном контексте;

  • обход кадров стека;

  • установку точек остановки и многое другое. 

Помимо консольной оболочки, доступной из командной строки, есть также расширение VS Code «Tarantool Lua Debugger» (скачать), которое поддерживает сценарии, аналогичные описанному выше консольному отладчику.

local dbg = require("luadebug")

dbg() -- Вызов оболочки отладчика

local a = 1

local function b()
    print("hello")

    local m = 1
    local b = 2
    local a = 1
    local c = m + b
    if c == 2 then
        b = 22
    end
end

if a == 1 then
    b()
    a = 2
    b()
end
$ tarantool dbg-example.lua 
luadebug: Loaded for 2.11.0-entrypoint-1031-gdc451913f
break via dbg() => debug-dbg.lua:3 in chunk at debug-dbg.lua:0
   1    local debugger = require 'luadebug'
   2    debugger()
   3 => local date = require 'datetime'
   4
   5    local T = date.new{hour = 3, tzoffset = '+0300'}
   6    print(T)
luadebug>

Демо: https://asciinema.org/a/560039 

В дополнение к использованию отладчика через вызов require('luadebug')(), о котором говорилось выше, можно использовать менее инвазивный подход — новый параметр -d. Таким образом, вы можете отлаживать Lua-скрипты напрямую:

$ tarantool -d debug.lua
Tarantool debugger 2.11.0-entrypoint-1031-gdc451913f
type 'help' for interactive help
luadebug: Loaded for 2.11.0-entrypoint-1031-gdc451913f
break via debug.lua => debug.lua:1 in chunk at debug.lua:0
   1 => local date = require 'datetime'
   2
   3    local T = date.new{hour = 3, tzoffset = '+0300'}
   4    print(T)

Обратите внимание! И консольный отладчик, и отладчик VS Code пока не поддерживают отладку кода с файберами. Это ограничение будет снято в будущих версиях.

Разработчикам, интересующимся отладкой Lua-кода, также может быть полезен встроенный инструмент профилирования памяти.

Enterprise edition: безопасность и интерактивный отладчик Lua-кода 

Версия Enterprise edition получила множество улучшений в области безопасности. И конечно, было сделано многое для разработчиков, например логирование по модулям, улучшенный HTTP-клиент и параметры для лучшей совместимости.

Представление для чтения (Read view)

Теперь в Tarantool Enterprise Edition можно создать единое представление для чтения данных. Объект представления обеспечивает доступ к статическому образу всех спейсов, существовавших на момент создания представления. Использование представления для чтения может обеспечить согласованность данных при выполнении длительных запросов. Для реализации представлений для чтения мы используем механизм копирования при записи (Copy-on-write), поэтому потребление памяти будет ограничено размером набора данных, обновляемых после создания представления.

Проще говоря, теперь в Tarantool можно проводить аналитические операции над данными, не затрагивая транзакционные операции (без дополнительной нагрузки, без остановки процессов). Например, интернет-магазины могут параллельно с обработкой запросов пользователей анализировать товарные остатки, в режиме реального времени составлять прогнозные модели и планировать поставки.

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

Создание спейса:

box.schema.create_space('my_space')
box.space.my_space:create_index('primary')
box.space.my_space:insert{1, 1}

Открытие режима чтения:

rv = box.read_view.open('my_read_view')

Обновление данных, хранящихся в спейсе:

box.space.my_space:replace{1, 2}
box.space.my_space:insert{2, 2}
box.space.my_space:select() -- Возвращает [(1, 2), (2, 2)]
rv.space.my_space:select()  -- Возвращает [(1, 1)]

Обратите внимание, что представления для чтения в настоящее время поддерживаются только движком Memtx.

PAP-SHA256

В новой версии Tarantool Enterprise Edition появились парольные политики и новый метод аутентификации пользователей — PAP-SHA256. Парольные политики позволяют повысить безопасность базы данных путем принудительного использования надежных паролей, установки максимального возраста пароля и так далее.

Пароли Tarantool хранятся в системном спейсе _user с криптографической хеш-функцией, так что если паролем является «x», то хранится хеш-пароль в виде длинной строки, например lL3OvhkIPOKh+Vn9Avlkx69M/Ck=. Когда клиент подключается к экземпляру Tarantool, тот отправляет случайное значение соли, которое клиент должен сложить вместе с хеш-паролем перед отправкой на экземпляр. Таким образом, изначальное значение «x» не хранится нигде, кроме как в голове самого пользователя, а хешированное значение никогда не передается по сети, кроме как в смешанном с солью виде. В отличие от стандартного и единственного ранее доступного метода аутентификации CHAP-SHA1, PAP-SHA256 применяет случайную соль к паролю пользователя перед хешированием и сохранением в базе данных, что делает этот метод устойчивым к атакам методом перебора с использованием радужных таблиц. Он также использует хеш-функцию SHA256, которая не имеет известных уязвимостей.

Включить метод аутентификации PAP-SHA256 для всех новых пользователей:

box.cfg({authtype = 'pap-sha256'})

Изменение установленного пароля пользователя для использования метода аутентификации:

PAP-SHA256.
box.schema.user.passwd('alice', 'topsecret')

Аутентификация с помощью PAP-SHA256 через net.box:

conn = require('net.box').connect(uri, {
    user = 'alice',
    password = 'topsecret',
    -- Указывать метод аутентификации необязательно, по умолчанию
    -- клиент будет использовать метод, установленный в конфигурации
    -- удаленного сервера (box.cfg.auth_type)
    auth_type = 'pap-sha256',
})

Важно: метод аутентификации PAP-SHA256 подразумевает передачу пароля пользователя в виде открытого текста по сетевому каналу, поэтому этот метод безопасно использовать только при условии, что соединение зашифровано. Коннекторы Tarantool не будут использовать этот метод, если не включен SSL/TLS.

И это не все

Наша команда разработчиков сделала еще много полезных улучшений, которые нельзя представить как новые функции, но они важны для успешного пользования платформой. Полный список изменений можно посмотреть в примечаниях к версиям. Многие исправления ошибок попадают в выпуски исправлений 2.10 и перечислены там: 2.10.5, 2.10.4, 2.10.3, 2.10.2, 2.10.1. Мы тщательно планируем реализацию новых функций, чтобы обеспечить обратную совместимость и возможность расширения. Теперь гораздо больше функций разработано с нуля с учетом беспрепятственного обновления, а также прямой и обратной совместимости.

Мы много работаем над рефакторингом кода, чтобы сделать его более безопасным и простым в обслуживании. В процесс разработки был добавлен анализатор CodeQL. Мы проанализировали множество отчетов этого и других анализаторов, чтобы повысить стабильность и безопасность. Идет работа с внутренними и внешними экспертами по безопасности, чтобы провести глубокий анализ возможных проблем. 

Будем рады видеть ваши отзывы.

Мы не останавливаемся на достигнутом и продолжаем работать над новыми улучшениями.

Регистрируйтесь и подключайтесь к вебинару 06 июня в 17:00 МСК. Узнайте, чем отличается Tarantool 2.11 от предыдущих версий и почему вам нужно на него мигрировать. Готовьте вопросы к разработчикам Tarantool, за самый интересный мы подарим специальный мерч.

В программе:

— особенности нового LTS-релиза Tarantool 2.11;

— демо от Кирилла Юхина, СТО Tarantool;

— планы по развитию Tarantool;

— Q&A-сессия со спикерами.

Спикеры: Владимир Салыкин, директор по продукту, и Кирилл Юхин, СТО Tarantool. 

Модератор: Павел Лапаев,   руководитель тренинг-центра VK Tech.

© Habrahabr.ru