Top.Mail.Ru
Tarantool » latest » Справочники » Справочник по встроенным модулям » Модуль net.box
 

Модуль net.box

Модуль net.box

Общие сведения

Модуль net.box включает в себя коннекторы для удаленных систем с базами данных. Одним из вариантов, который рассматривается позднее, является подключение к MySQL, MariaDB или PostgreSQL (см. справочник по Модулям СУБД SQL). Другим вариантом, который рассматривается в данном разделе, является подключение к экземплярам Tarantool-сервера по сети.

Можно вызвать следующие методы:

  • require('net.box') для получения объекта net.box (который называется net_box для примеров в данном разделе),
  • net_box.connect() для подключения и получения объекта подключения (который называется conn для примеров в данном разделе),
  • другие процедуры net.box(), передающие conn: для выполнения запросов в удаленной системе базы данных,
  • conn:close для отключения.

Все методы net.box безопасны для файберов, то есть можно безопасно обмениваться и использовать один и тот же объект подключения в нескольких файберах одновременно. Фактически так лучше всего работать в Tarantool’е. Когда несколько файберов используют одно соединение, все запросы передаются по одному сетевому сокету, но каждый файбер получает правильный ответ. Уменьшение количества активных сокетов снижает затрату ресурсов на системные вызовы и увеличивает общую производительность сервера. Однако, в некоторых случаях отдельного соединения недостаточно – например, когда необходимо отдавать приоритет разным запросам или использовать различные идентификаторы при аутентификации.

В большинстве методов net.box можно использовать заключительный аргумент {options}, который может быть:

  • {timeout=...}. Например, метод с заключительным аргументом {timeout=1.5} остановится через 1,5 секунды на локальном узле, хотя это не гарантирует, что выполнение остановится на удаленном сервере.
  • {buffer=...}. Например, см. модуль buffer.
  • {is_async=...}. Например, метод с заключительным аргументом {is_async=true} не будет ждать результата выполнения запроса. См. описание is_async.
  • {on_push=... on_push_ctx=...}. Для получения внеполосных сообщений. См. описание box.session.push.

На диаграмме ниже представлены возможные состояния и варианты перехода из одного состояния в другое:

net_states.svg

На этой диаграмме:

  • Работа начинается с начального состояния „initial“.
  • Выполнение метода net_box.connect() переводит состояние в „connecting“, создается рабочий файбер.
  • Если требуются аутентификация и загрузка схемы, можно позднее повторно войти в состояние загрузки схемы „fetch_schema“ из активного „active“, если запрос не будет выполнен из-за ошибки несовпадения версий схемы, то есть будет вызвана перезагрузка схемы.
  • Метод conn.close() изменяет состояние на закрытое „closed“ и отключает рабочий процесс. Если транспорт уже находится в состоянии ошибки „error“, close() не делает ничего.

Указатель

Ниже приведен перечень всех функций модуля net.box.

Имя Назначение
net_box.connect()
net_box.new()
net_box.self
Создание подключения
conn:ping() Выполнение команды проверки состояния PING
conn:wait_connected() Ожидание активности или закрытия подключения
conn:is_connected() Проверка активности или закрытия подключения
conn:wait_state() Ожидание нужного состояния
conn:close() Закрытие подключения
conn.space.space-name:select{field-value} Выбор одного или нескольких кортежей
conn.space.space-name:get{field-value} Выбор кортежа
conn.space.space-name:insert{field-value} Вставка кортежа
conn.space.space-name:replace{field-value} Вставка или замена кортежа
conn.space.space-name:update{field-value} Обновление кортежа
conn.space.space-name:upsert{field-value} Обновление кортежа
conn.space.space-name:delete{field-value} Удаление кортежа
conn:eval() Оценка и выполнение выражения в строке
conn:call() Вызов хранимой процедуры
conn:timeout() Установка времени ожидания
conn:on_connect() Определение триггера на подключение
conn:on_disconnect() Определение триггера на отключение
conn:on_schema_reload() Определение триггера при изменении схемы
net_box.connect(URI[, {option[s]}])
net_box.new(URI[, {option[s]}])

Примечание

Имена connect() и new() являются синонимами: предпочтительным будет connect(), а new() обеспечивает поддержку обратной совместимости.

Создание нового подключения. Подключение устанавливается по требованию во время первого запроса. Можно повторно установить подключение автоматически после отключения (см. ниже опцию reconnect_after). Возвращается объект conn, который поддерживает методы создание удаленных запросов, таких как select, update или delete.

Возможные опции:

  • user/password: есть два способа подключения к удаленному хосту: с использованием URI или параметров user (пользователь) и password (пароль). Например, вместо connect('username:userpassword@localhost:33301') можно ввести connect('localhost:33301', {user = 'имя-пользователя', password='пароль-пользователя'}).

  • wait_connected: по умолчанию, создание подключения блокируется до тех пор, пока подключение не будет установлено, но передача wait_connected=false заставит метод сразу же вернуться. Передача времени ожидания заставит метод ждать до возвращения (например, wait_connected=1.5 заставит ожидать подключения максимум 1,5 секунды).

    Примечание

    Если присутствует reconnect_after, wait_connected проигнорирует неустойчивые отказы. Ожидание заканчивается, когда подключение установлено или явным образом закрыто.

  • reconnect_after: net.box автоматически подключается повторно в случае разрыва соединения или провала попытки подключения. В таком случае неустойчивые сетевые отказы становятся очевидными. Повторное подключение выполняется автоматически в фоновом режиме, поэтому запросы/обращения, не выполненные по причине потери соединения, явным образом выполняются повторно. Количество повторов не ограничено, попытки подключения выполняются в течение указанного времени ожидания (например, reconnect_after=5 – 5 секунд). После явного закрытия подключения или удаления сборщиком мусора в Lua попытки соединения повторно не выполняются. Значение по умолчанию для параметра reconnect_after, как и для других connect опций, равно nil.

  • call_16: [с 1.7.2] по умолчанию, подключения net.box соответствуют команде CALL нового бинарного протокола, который не поддерживает обратную совместимость с предыдущими версиями. Команда нового бинарного протокола для вызова CALL больше не ограничивает функцию в возврате массива кортежей и позволяет возвращать произвольный результат в формате MsgPack/JSON, включая scalar (скалярные значения), nil (нулевые значения) и void (пусто). Старый метод CALL оставлен нетронутым для обратной совместимости. В следующей основной версии он будет удален. Все драйверы для языков программирования будут постепенно переведены на использование нового метода CALL. Для подключения к экземпляру Tarantool’а, в котором используется старый метод CALL, укажите call_16=true.

  • console: в зависимости от значения параметра поддерживаются различные методы (как если бы возвращались экземпляры разных классов). Если console = true, можно использовать методы conn: close(), is_connected(), wait_state(), eval() (в этом случае поддерживаются и бинарный сетевой протокол, и протокол Lua-консоли). Если console = false (по умолчанию), также можно использовать методы conn для работы с базой данных (в этом случае поддерживается только бинарный протокол). Устарел: console = true объявлен устаревшим, вместо него следует использовать console.connect().

  • connect_timeout: количество секунд ожидания до возврата ошибки «error: Connection timed out».

Параметры:
  • URI (string) – URI объекта подключения
  • options – возможные опции: user, password, wait_connected, reconnect_after, call_16, console и connect_timeout
возвращает:

объект подключения

тип возвращаемого значения:
 

пользовательские данные

Примеры:

conn = net_box.connect('localhost:3301')
conn = net_box.connect('127.0.0.1:3302', {wait_connected = false})
conn = net_box.connect('127.0.0.1:3303', {reconnect_after = 5, call_16 = true})
object self

Для локального Tarantool-сервера есть заданный объект всегда установленного подключения под названием net_box.self. Он создан с целью облегчить полиморфное использование API модуля net_box. Таким образом, conn = net_box.connect('localhost:3301') можно заменить на conn = net_box.self.

Однако, есть важно отличие встроенного подключения от удаленного:

  • При встроенном подключении запросы без изменения данных не передают управление. При использовании удаленного подключения любой запрос может передавать управление исходя из правил неявной передачи управления, и состояние базы данных может измениться к тому времени, как управление вернется.
  • Не учитывается ни один параметр, передаваемый в запросе (is_async, on_push, timeout).
object conn
conn:ping([options])

Выполнение команды проверки состояния PING.

Параметры:
  • options (table) – поддерживается опция timeout=секунды
возвращает:

true (правда), если выполнено, false (ложь) в случае ошибки

тип возвращаемого значения:
 

boolean (логический)

Пример:

net_box.self:ping({timeout = 0.5})
conn:wait_connected([timeout])

Ожидание активности или закрытия подключения.

Параметры:
  • timeout (number) – в секундах
возвращает:

true (правда) при подключении, false (ложь), если не выполнено.

тип возвращаемого значения:
 

boolean (логический)

Пример:

net_box.self:wait_connected()
conn:is_connected()

Проверка активности или закрытия подключения.

возвращает:true (правда) при подключении, false (ложь), если не выполнено.
тип возвращаемого значения:
 boolean (логический)

Пример:

net_box.self:is_connected()
conn:wait_state(state[s][, timeout])

[с 1.7.2] Ожидание нужного состояния.

Параметры:
  • states (string) – необходимое состояние
  • timeout (number) – в секундах
возвращает:

true (правда) при подключении, false (ложь) при окончании времени ожидания или закрытии подключения

тип возвращаемого значения:
 

boolean (логический)

Примеры:

-- бесконечное ожидание состояния 'active':
conn:wait_state('active')

-- ожидание в течение максимум 1,5 секунд:
conn:wait_state('active', 1.5)

-- бесконечное ожидание состояния `active` или `fetch_schema`:
conn:wait_state({active=true, fetch_schema=true})
conn:close()

Закрытие подключения.

Объекты подключения удаляются сборщиком мусора в Lua, как и любой другой Lua-объект, поэтому удалять их явным образом необязательно. Однако, поскольку close() представляет собой системный вызов, лучше всего закрыть соединение явным образом, когда оно больше не используется, с целью ускорения работы сборщика мусора.

Пример:

conn:close()
conn.space.<space-name>:select({field-value, ...} [, {options}])

conn.space.имя-спейса:select({...}) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:select{...} (детали). В дополнение см. Модуль buffer и skip-header.

Пример:

conn.space.testspace:select({1,'B'}, {timeout=1})

Примечание

Исходя из правил неявной передачи управления, локальный запрос box.space.имя-спейса:select{...} не передает управление, а удаленный conn.space.имя-спейса:select{...} передаст, поэтому глобальные переменные или кортежи в базе данных могут измениться во время удаленного conn.space.имя-спейса:select{...}.

conn.space.<space-name>:get({field-value, ...} [, {options}])

conn.space.имя-спейса:get(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:get(...) (детали).

Пример:

conn.space.testspace:get({1})
conn.space.<space-name>:insert({field-value, ...} [, {options}])

conn.space.имя-спейса:insert(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:insert(...) (детали). В дополнение см. Модуль buffer и skip-header.

Пример:

conn.space.testspace:insert({2,3,4,5}, {timeout=1.1})
conn.space.<space-name>:replace({field-value, ...} [, {options}])

conn.space.имя-спейса:replace(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:replace(...) (детали). В дополнение см. Модуль buffer и skip-header.

Пример:

conn.space.testspace:replace({5,6,7,8})
conn.space.<space-name>:update({field-value, ...} [, {options}])

conn.space.имя-спейса:update(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:update(...).

Пример:

conn.space.Q:update({1},{{'=',2,5}}, {timeout=0})
conn.space.<space-name>:upsert({field-value, ...} [, {options}])

conn.space.имя-спейса:upsert(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:upsert(...) (детали). В дополнение см. Модуль buffer и skip-header.

conn.space.<space-name>:delete({field-value, ...} [, {options}])

conn.space.имя-спейса:delete(...) – это удаленный вызов, аналогичный локальному вызову box.space.имя-спейса:delete(...).(детали). В дополнение см. Модуль buffer и skip-header.

conn:eval(Lua-string[, {arguments}[, {options}]])

conn:eval(Lua-строка) оценивает и выполняет выражение в Lua-строке, которое может представлять собой любое выражение или несколько выражений. Требуются права на выполнение; если у пользователя таких прав нет, администратор может их выдать с помощью box.schema.user.grant(имя-пользователя, 'execute', 'universe').

Чтобы гарантировать, что conn:eval вернет то, что возвращает выражение на Lua, начните Lua-строку со слова «return» (вернуть).

Примеры:

tarantool> --Lua-строка
tarantool> conn:eval('function f5() return 5+5 end; return f5();')
---
- 10
...
tarantool> --Lua-строка, {аргументы}
tarantool> conn:eval('return ...', {1,2,{3,'x'}})
---
- 1
- 2
- [3, 'x']
...
tarantool> --Lua-строка, {аргументы}, {парметры}
tarantool> conn:eval('return {nil,5}', {}, {timeout=0.1})
---
- [null, 5]
...
conn:call(function-name[, {arguments}[, {options}]])

conn:call('func', {'1', '2', '3'}) – это удаленный вызов, аналогичный func('1', '2', '3'). Таким образом, conn:call представляет собой удаленный вызов хранимой процедуры. conn:call возвращает то, что возвращает функция.

Ограничение: вызванная функция не может вернуть функцию, например, если func2 определяется как function func2 () return func end, то conn:call(func2) вернет ошибку «error: unsupported Lua type „function“».

Примеры:

tarantool> -- создание 2 функций с conn:eval()
tarantool> conn:eval('function f1() return 5+5 end;')
tarantool> conn:eval('function f2(x,y) return x,y end;')
tarantool> -- вызов первой функции без параметров и опций
tarantool> conn:call('f1')
---
- 10
...
tarantool> -- вызов второй функции с двумя параметрами и одной опцией
tarantool> conn:call('f2',{1,'B'},{timeout=99})
---
- 1
- B
...
conn:timeout(timeout)

timeout(...) – это надстройка, которая определяет время ожидания для запроса. С версии 1.7.4 этот метод объявлен устаревшим – лучше передать значение времени ожидания с помощью параметра {options}.

Пример:

conn:timeout(0.5).space.tester:update({1}, {{'=', 2, 15}})

Хотя timeout(...) объявлен устаревшим, все удаленные вызовы поддерживают его. Использование надстройки обеспечивает совместимость API удаленного соединения с локальным, поэтому отпадает необходимость в отдельном аргументе timeout, который проигнорирует локальная версия. После отправки запроса его нельзя отменить с удаленного сервера даже по истечении времени задержки: окончание времени задержки прерывает только ожидание ответа от удаленного сервера, а не сам запрос.

conn:request(... {is_async=...})

{is_async=true|false} – это опция, которую можно применить во всех запросах net_box, включая conn:call, conn:eval и запросы conn.space.space-name.

По умолчанию, is_async=false, что означает, что запросы будут синхронными для файбера. Файбер блокируется в ожидании ответа на запрос или до истечения времени ожидания. До версии Tarantool’а 1.10 единственным способом выполнения асинхронных запросов было использование отдельных файберов.

is_async=true означает, что запросы будут асинхронными для файбера. Запрос вызывает передачу управления, но файбер не входит в режим ожидания. Сразу же возвращается результат, но это будет не результат запроса, а объект, который может использовать вызывающая программа для получения результат запроса.

У такого сразу же возвращаемого объекта, который мы называем «future» (будущий), есть собственные методы:

  • future:is_ready() вернет true (правда), если доступен результат запроса,
  • future:result() используется для получения результата запроса (возвращает ответ на запрос или nil в случае, если ответ еще не готов или произошла какая-либо ошибка),
  • future:wait_result(timeout) будет ждать, когда результат запроса будет доступен, а затем получит его или выдаст ошибку, если по истечении времени ожидания результат не получен.
  • future:discard() откажется от объекта.

В обычной ситуации пользователь введет команду future=имя-запроса(...{is_async=true}), а затем либо цикл с проверкой future:is_ready() до тех пор, пока он не вернет true, и получением результата с помощью request_result=future:result(), либо же команду request_result=future:wait_result(...). Возможен вариант, когда клиент проверяет наличие внеполосных сообщений от сервера, вызывая в цикле pairs() – см. box.session.push().

Можно использовать future:discard(), чтобы соединение забыло об ответе – если получен ответ для отброшенного объекта, то он будет проигнорирован, так что размер таблицы запросов будет уменьшен, а другие запросы будут выполняться быстрее.

Пример:

tarantool> future = conn.space.tester:insert({900},{is_async=true})
---
...
tarantool> future
---
- method: insert
  response: [900]
  cond: cond
  on_push_ctx: []
  on_push: 'function: builtin#91'
...
tarantool> future:is_ready()
---
- true
...
tarantool> future:result()
---
- [900]
...

Как правило, {is_async=true} используется только при большой загрузке (более 100 000 запросов в секунду) и большой задержке чтения (более 1 секунды), или же при необходимости отправки нескольких одновременных запросов, которые собирают ответы (что иногда называется «отображение-свертка»).

Примечание

Хотя окончательный результат асинхронного запроса не отличается от результата синхронного запроса, у него другая структура: таблица, а не неупакованные значения.

Триггеры

В модуле net.box можно использовать следующие триггеры:

conn:on_connect([trigger-function[, old-trigger-function]])

Определение триггера, исполняемого, когда устанавливается новое соединение (и при условии, что аутентификация и сборка схемы завершены) при таком событии, как net_box.connect. Если триггер не срабатывает и выкидывает исключение, статус подключения меняется на „error“.В таком случае соединение прерывается, независимо от значения опции reconnect_after. Может вызываться столько раз, сколько раз происходит переподключение, если значение параметра reconnect_after больше нуля.

Параметры:
  • trigger-function (function) – функция, в которой будет триггер. В качестве первого аргумента берет объект conn
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращает:

nil или указатель функции

conn:on_disconnect([trigger-function[, old-trigger-function]])

Определение триггера, исполняемого после закрытия соединения. Если функция с триггером вызывает ошибку, то ошибка записывается в журнал, в противном случае записей не будет. Выполнение прекращается после явного закрытия соединения или удаления сборщиком мусора в Lua.

Параметры:
  • trigger-function (function) – функция, в которой будет триггер. В качестве первого аргумента берет объект conn
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращает:

nil или указатель функции

conn:on_schema_reload([trigger-function[, old-trigger-function]])

Определение триггера, исполняемого во время выполнения определенной операции на удаленном сервере после обновления схемы. Другими словами, если запрос к серверу не выполняется из-за ошибки несовпадения версии схемы, происходит перезагрузка схемы.

Параметры:
  • trigger-function (function) – функция, в которой будет триггер. В качестве первого аргумента берет объект conn
  • old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращает:

nil или указатель функции

Примечание

Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.

Если не указан ни один параметр, ответом будет список существующих функций с триггером.

Подробная информация о характеристиках триггера находится в разделе Триггеры.

Пример

Ниже приводится пример использования большинства методов net.box.

Данный пример сработает на конфигурации из песочницы, предполагается, что:

  • экземпляр Tarantool’а запущен на localhost 127.0.0.1:3301,
  • создан спейс под названием tester с первичным числовым ключом и кортежем, в котором есть ключ со значением= 800,
  • у текущего пользователя есть права на чтение, запись и выполнение.

Ниже приведены команды для быстрой настройки песочницы:

box.cfg{listen = 3301}
s = box.schema.space.create('tester')
s:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}})
t = s:insert({800, 'TEST'})
box.schema.user.grant('guest', 'read,write,execute', 'universe')

А здесь приведен пример:

tarantool> net_box = require('net.box')
---
...
tarantool> function example()
         >   local conn, wtuple
         >   if net_box.self:ping() then
         >     table.insert(ta, 'self:ping() succeeded')
         >     table.insert(ta, '  (no surprise -- self connection is pre-established)')
         >   end
         >   if box.cfg.listen == '3301' then
         >     table.insert(ta,'The local server listen address = 3301')
         >   else
         >     table.insert(ta, 'The local server listen address is not 3301')
         >     table.insert(ta, '(  (maybe box.cfg{...listen="3301"...} was not stated)')
         >     table.insert(ta, '(  (so connect will fail)')
         >   end
         >   conn = net_box.connect('127.0.0.1:3301')
         >   conn.space.tester:delete({800})
         >   table.insert(ta, 'conn delete done on tester.')
         >   conn.space.tester:insert({800, 'data'})
         >   table.insert(ta, 'conn insert done on tester, index 0')
         >   table.insert(ta, '  primary key value = 800.')
         >   wtuple = conn.space.tester:select({800})
         >   table.insert(ta, 'conn select done on tester, index 0')
         >   table.insert(ta, '  number of fields = ' .. #wtuple)
         >   conn.space.tester:delete({800})
         >   table.insert(ta, 'conn delete done on tester')
         >   conn.space.tester:replace({800, 'New data', 'Extra data'})
         >   table.insert(ta, 'conn:replace done on tester')
         >   conn.space.tester:update({800}, {{'=', 2, 'Fld#1'}})
         >   table.insert(ta, 'conn update done on tester')
         >   conn:close()
         >   table.insert(ta, 'conn close done')
         > end
---
...
tarantool> ta = {}
---
...
tarantool> example()
---
...
tarantool> ta
---
- - self:ping() succeeded
  - '  (no surprise -- self connection is pre-established)'
  - The local server listen address = 3301
  - conn delete done on tester.
  - conn insert done on tester, index 0
  - '  primary key value = 800.'
  - conn select done on tester, index 0
  - '  number of fields = 1'
  - conn delete done on tester
  - conn:replace done on tester
  - conn update done on tester
  - conn close done
...