Гайд по использованию Lua-скриптов в Redis
Краткий гайд по написанию и запуску Lua-скриптов на Redis.
16К открытий18К показов
Что такое язык Lua?
Язык программирования Lua появился в 1993 году. По своей структуре он является компактным языком программирования, который можно встраивать практически в любое приложение — от World of Warcraft до веб-сервера Nginx. Ну и конечно же, в Redis, о котором далее и пойдёт речь.
Благодаря Lua в Redis возможно встраивать собственные скриптовые расширения для базы данных. Вызов скриптов выглядит следующим образом:
Далее сам Lua-скрипт:
Что более важно, вы можете запускать скрипты в качестве “умных транзакций”. Это позволяет обрабатывать ошибки в рантайме, не останавливая приложение. Безусловно, то, насколько “умными” будут эти транзакции, зависит целиком и полностью от вас.
Ключи и аргументы
Для обращения к скрипту неплохо бы было передать ему ключи и аргументы. Например, как в нижеприведённом коде:
В конце EVAL мы видим ноль — это количество ключей, переданных скрипту. Но если вместо ноля написать 2 foo bar fizz buzzthen, первые два элемента foo и bar будут переданы в качестве ключей, а fizz и buzz — в качестве аргументов.
Ключи доступны Lua-скрипту в таблице KEYS. Таблица в Lua — это ассоциативный массив, который также используется в качестве массива из одного элемента. Если помимо ключей используются аргументы, они будут доступны в таблице ARGV, например:
В Lua .. используется в качестве оператора объединения, так что здесь в качестве возвращаемого значения мы получаем аргумент, привязанный к пробелу, и название ключа, которое было передано в качестве аргумента:
Никакой магии в KEYS, это просто строка, так что нам по-прежнему нужно получить их значение.
Что касается вызова Redis из Lua, можно использовать функцию redis.call(). Например:
Прим. автора Если в процессе объединения вы получаете ошибку “attempt to concatenate a boolean value” (попытка объединения значений булевого типа), скорее всего name:first не было присвоено какое-либо значение.
Таким образом, скрипт взял параметр, нашёл значение ключа и вернул в качестве вывода созданную строку.
Однако помимо EVAL есть и другой способ передать скрипт на сервер. Например, используя аргументы команды redis-cli. Попробуем написать чуть более сложный скрипт:
Сохраним его как longhello.lua и выполним в командной строке:
Итак, мы запускаем redis-cli, добавляем параметры -h, -p и -a для связи с базой данных. Затем идёт --eval, позволяющий указать имя файла, в виде которого скрипт отправится на сервер. Также нашему скрипту понадобятся ключи и аргументы. В данном случае ключами являются указанные до первой запятой параметры команды.
Сложные скрипты
Следующий случай наглядно демонстрирует, как Lua решает одну небольшую проблему. Допустим, разные пользователи или разработчики увеличивают счётчики в большой структуре данных. Например, region:one увеличивает count:emea, count:usa, count:atlantic, в то время как region:two затрагивает лишь count:usa. Эти счётчики могут быть добавлены позже, но вдруг вам важно убедиться, что добавятся они все разом? Самое время вспомнить про “умные транзакции”.
Добавим все наши регионы в список:
Создадим локальную переменную:
Начнём с переменной-счётчика — он будет считать все операции по увеличению наших округов.
Теперь запросим у Redis все значения списка, относящиеся к первому ключу.
Здесь мы запустили цикл, в котором функция ipairs() просмотрит каждую задействованную Lua-таблицу и передаст из неё ключ.
С каждым вызовом мы увеличиваем указанный ключ, а заодно и наш счётчик.
После окончания цикла мы получаем конечное число итераций. Сохраним итоговый скрипт и запустим его на сервере:
В таблице будут содержаться следующие значения:
Значения для region.two:
Но что, если бы во время выполнения скрипта произошла ошибка? Он просто продолжил бы выполняться, игнорируя её. Для вывода деталей ошибки следует использовать redis.pcall().
Кэширование скриптов
Для того чтобы не загружать скрипт каждый раз перед выполнением, можно использовать команду SCRIPT LOAD для загрузки скрипта в кэш. Рассмотрим пример использования из командной строки:
Здесь $(cat broadcast.lua) превращает наш скрипт в аргумент. А шестнадцатеричное число ниже — SHA1-подпись нашего скрипта. Её можно использовать для его последующего вызова командой EVALSHA:
Также есть команды для проверки наличия скрипта на сервере и его удаления – SCRIPT EXISTS и SCRIPT FLUSH соответственно.
Не всё так просто
После довольно небольшого промежутка времени (по умолчанию — 5 секунд) Lua-скрипты начнут выдавать ошибки в ответ на запросы — в таком случае возможно только “убить” скрипт командой KILL SCRIPT либо выключить сервер командой SHUTDOWN NOSAVE. С другой стороны, 5 секунд — очень щедрое ограничение, ведь ваши скрипты должны выполняться буквально в течение миллисекунд. И на это есть очень веская причина: во время выполнения ваших скриптов все остальные процессы приостанавливаются.
Заключение
Итак, в этой статье мы рассмотрели примеры написания простых и сложных Lua-скриптов, их вызов из Redis, а также запись и хранение на сервере.
16К открытий18К показов



