tarantool: Библиотека для работы с tarantool из nginx с встроенным Lua модулем или с nginx-module-lua
Установка
Если вы еще не настроили подписку на RPM репозиторий, зарегистрируйтесь. Затем вы можете продолжить с следующими шагами.
CentOS/RHEL 7 или Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-tarantool
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-tarantool
Чтобы использовать эту Lua библиотеку с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-tarantool v0.3, выпущенную 21 октября 2015 года.
Введение
Это библиотека для подключения к tarantool NoSQL базе данных. Эта база данных имеет очень интересные функции, которые делают ее своего рода мостом между традиционной SQL базой данных и документно-ориентированными хранилищами, такими как CouchDB.
Это форк другого проекта, который меня не устраивал. Он обильно документирован и обновляется в соответствии с API tarantool. Особенно с поддержкой команды upsert.
Еще одна вещь, о которой стоит помнить, это то, что библиотека старается быть последовательной между тем, как команды update и upsert вызываются в консоли с использованием Lua, и тем, как работает API. В частности, номера полей. В консоли номер поля учитывает наличие первичного индекса как первого поля. Следовательно, любое поле, которое идет после, будет иметь позицию, которая это учитывает. В частности, при указании операторов, которые нужно использовать для операций update или upsert.
Использование
Создание соединения
local tar = require 'resty.tarantool'
local tar, err = tnt:new({
host = '127.0.0.1',
port = 3301,
user = 'luser',
password = 'some password',
socket_timeout = 2000,
})
luser с паролем some password. См. Руководство Tarantool по аутентификации для получения подробной информации о том, как настраивать пользователей и назначать им привилегии.
Таймаут сокета (прием и отправка) составляет 2 секунды (2000 мс).
set_timeout
settimeout(<объект соединения>, <таймаут в мс>)
Устанавливает как таймауты отправки, так и получения в миллисекундах для данного сокета.
tnt:set_timeout(5000) -- 5s таймаут для операций отправки/получения
Функция возвращает true, если установка прошла успешно, nil, если нет. Обратите внимание, что для того, чтобы таймаут вступил в силу, эту функцию необходимо вызвать до установления соединения, т.е. до вызова функции connect. В качестве альтернативы таймаут можно указать при создании объекта соединения (cosocket).
connect
connect(<объект соединения>)
Подключает сокет, созданный выше, к порту и адресу, указанным при создании объекта соединения.
tar:connect()
nil, если нет.
set_keepalive
set_keepalive(<объект соединения>)
Сохраняет созданное соединение в пул соединений, чтобы соединение оставалось активным между несколькими запросами.
tar:set_keepalive()
Функция возвращает true, если сокет успешно помещен в пул соединений (установлен keepalive). nil, если нет.
disconnect
disconnect(<объект соединения>)
Закрывает соединение с данным сервером tarantool, работающим по указанному адресу и порту.
tar:disconnect()
Функция возвращает true, если соединение успешно закрыто. nil, если нет.
ping
Команда ping полезна для мониторинга сервера tarantool, чтобы проверить, доступен ли он. Если он доступен для запросов, возвращает строку PONG.
tar:ping()
-- возвращает PONG
select
Операция select запрашивает данную базу данных (пространство) для извлечения записей.
select(<объект соединения>, <имя пространства>, <индекс>, <ключ>, <опции>)
где <опции> является необязательным аргументом, который может состоять из таблицы, которая может иметь следующие ключи:
offset: количество записей, которые нужно пропустить при выполнении запроса.limit: максимальное количество записей для возврата.iterator: число, указывающее, какой итератор использовать. Указывается таблицей:
local iterator_keys = {
EQ = 0, -- равенство
REQ = 1, -- обратное равенство
ALL = 2, -- все кортежи в индексе
LT = 3, -- меньше чем
LE = 4, -- меньше или равно
GE = 5, -- больше или равно
GT = 6, -- больше чем
BITSET_ALL_SET = 7, -- биты в битовой маске все установлены
BITSET_ANY_SET = 8, -- любой из битов в битовой маске установлен
BITSET_ALL_NOT_SET = 9, -- ни один из битов в битовой маске не установлен
}
Примеры select
Запрос пространства _space (БД) для получения идентификатора пространства _index.
local res, err = tar:select('_space', 'name', '_index')
-- ответ:
[2881,"_index","memtx",0,"",
[{"name":"id","type":"num"},
{"name":"iid","type":"num"},
{"name":"name","type":"str"},
{"name":"type","type":"str"},
{"name":"opts","type":"array"},
{"name":"parts","type":"array"}]]]
box.space._space.index.name:select{ '_index' }
Запрос пространства 'activities' для получения активностей с price меньше 300
-- Примечание. price является индексом пространства activities.
local res, err = tar:select('activities', 'price', 300, { iterator = 'LT' })
box.space.activities.index.price:select({ 300 }, { iterator = 'LT' })
insert
insert(<объект соединения>, <имя пространства>, <кортеж>)
где <кортеж> — это кортеж, который нужно вставить в <пространство>, устанавливая первичный индекс, который уникален, на значение, указанное в кортеже.
Функция возвращает вставленную запись, если операция прошла успешно.
Примеры insert
local res, err = tar:insert('activities', { 16, 120, { activity = 'surf', price = 121 } })
-- ответ:
[[16,120,{"activity":"surf","price":121}]]
box.space.activities:insert({16, 120, { activity = 'surf', price = 121 }})
replace
replace(<объект соединения>, <имя пространства>, <кортеж>)
Команда replace аналогична по вызову и сигнатуре команде insert. Но теперь мы ищем замену записи, которая уже существует, вместо вставки новой. Нам снова нужно значение первичного уникального индекса. Но теперь значение должно существовать, чтобы операция прошла успешно. Если операция проходит успешно, возвращается запись с замененными значениями.
Примеры replace
local res, err = tar:replace('activities', { 16, 120, { activity = 'surf', price = 120 } })
-- ответ:
[[16,120,{"activity":"surf","price":120}]]
Вышеуказанный запрос эквивалентен запросу в консоли:
box.space.activities:update({ 16, 120, { activity = 'surf', price = 120 }})
update
update(<объект соединения>, <имя пространства>, <индекс>, <ключ>, <список операторов>)
где <список операторов> — это список операторов, как указано в руководстве tarantool.
Пара (<индекс>, <ключ>) уникально идентифицирует запись, т.е. <ключ> — это значение первичного (уникального) <индекса>.
<список операторов> — это таблица следующего вида:
{ <оператор>, <позиция поля>, <значение> }
+для добавления к числовому полю.-для вычитания из числового поля.&для побитовой операции AND между двумя беззнаковыми целыми числами.|для побитовой операции OR между двумя беззнаковыми целыми числами.^для побитовой операции XOR между двумя беззнаковыми целыми числами.:для слияния строк.!для вставки поля.#для удаления поля.=для присвоения заданного значения полю.
возвращает обновленную запись, если операция успешна.
Примеры update
local res, err = tar:update('activities', 'primary', 16, { { '=', 2, 341 }, { '=', 3, { activity = 'kitesurfing', price = 341 }}} )
-- ответ:
[16,341,{"activity":"kitesurfing","price":341}]]
primary 16, которую мы вставили выше, была обновлена.
Вышеуказанный запрос эквивалентен запросу в консоли:
box.space.activities.index.primary({ 16 }, { { '=', 2, 341 }, { '=', 3, { activity = 'kitesurfing', price = 341 }}})
upsert
upsert(<объект соединения>, <имя пространства>, <ключ>, <список операторов>, <новый кортеж>)
Помимо аргумента <новый кортеж>, сигнатура функции аналогична update. На самом деле upsert — это две команды в одной. update, если запись, указанная парой (<индекс>, <ключ>), существует, и insert, если нет. Ключ — это значение из первичного индекса, т.е. уникально. <новый кортеж> — это кортеж, который будет вставлен, если значение <ключа> не существует в <индексе>. Возвращает пустую таблицу {}, если операция успешна. Если операция не удалась, возвращает nil.
Примеры upsert
insert.
local res, err = tar:upsert('activities', 17, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 17, 450, { activity = 'waterski', price = 365 }})
-- ответ:
{}
{ 18, 450, { activity = 'waterski', price = 365 }}
box.space.activities:upsert({ 17 }, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 17, 450, { activity = 'waterski', price = 365 }})
local res, err = tar:upsert('activities', 17, { { '=', 2, 450 }, { '=', 3, { activity = 'submarine tour 8', price = 450 }}}, { 18, 285, { activity = 'kitesurfing', price = 285 }})
-- ответ:
{}
primary (уникальном).
delete
delete(<объект соединения>, <пространство>, <ключ>)
удаляет запись, уникально указанную <ключом>, из <пространства>. Обратите внимание, что <ключ> должен принадлежать первичному (уникальному) индексу. Возвращает удаленную запись, если операция успешна.
Примеры delete
local response, err = tar:delete('activities', 17)
-- ответ:
[17,450,{"activity":"waterski","price":365}]]
Вышеуказанный запрос эквивалентен запросу в консоли:
box.space.activities:delete({ 17 })
call
call(<объект соединения>, <proc>, <args>)
Вызывает хранимую процедуру (функцию Lua) на сервере tarantool, к которому мы подключены. Возвращает результаты вызова.
Примеры call
Поскольку консоль tarantool является Lua REPL, любую функцию можно вызвать, если она доступна в окружении.
local res, err = tar:call('table.concat', { {'hello', ' ', 'world' } })
-- ответ:
[["hello world"]]
table.concat из библиотеки table для объединения таблицы:
{'hello', ' ', 'world' }
table.concat({'hello', ' ', 'world' })
Для множества примеров хранимых процедур tarantool смотрите репозиторий; https://github.com/mailru/tarlua
hide_version_header
hide_version_header(<объект соединения>)
По умолчанию каждый ответ отправляет пользовательский HTTP заголовок X-Tarantool-Version с версией сервера tarantool.
X-Tarantool-Version: 1.6.6-191-g82d1bc3
Вызов hide_version_header удаляет заголовок.
tar:hide_version_header()
Он не возвращает значений.
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-tarantool.