Скриптинг Lua в Redis

RedisBeginner
Практиковаться сейчас

Введение

В этой лабораторной работе вы изучите Redis Lua Scripting, сосредоточившись на выполнении Lua-скриптов непосредственно в Redis для эффективного выполнения сложных операций. Эта лабораторная работа охватывает использование команды EVAL для выполнения скриптов, передачу аргументов скриптам, загрузку скриптов с помощью SCRIPT LOAD и запуск загруженных скриптов с помощью EVALSHA.

Мы начнем с выполнения простого Lua-скрипта, который увеличивает счетчик Redis с помощью EVAL, демонстрируя, как указать скрипт, количество ключей, к которым он обращается, и имена ключей. Затем мы узнаем, как загружать скрипты в Redis и выполнять их, используя их SHA1-хеш, что повышает производительность, избегая повторной передачи скрипта.

Выполнение Lua-скрипта с помощью EVAL

В этом шаге мы рассмотрим, как выполнять Lua-скрипты непосредственно в Redis с помощью команды EVAL. Это позволяет выполнять сложные операции с вашими данными в одном запросе, снижая задержку сети и повышая производительность.

Прежде чем мы начнем, давайте разберемся с основами EVAL. Команда EVAL принимает два основных аргумента:

  1. Сам Lua-скрипт в виде строки.
  2. Количество ключей, к которым скрипт будет обращаться, за которым следуют фактические имена ключей и любые дополнительные аргументы, которые вы хотите передать скрипту.

Вот простой пример для начала. Мы создадим Lua-скрипт, который увеличивает счетчик Redis и возвращает новое значение.

  1. Откройте свой терминал и подключитесь к серверу Redis, используя интерфейс командной строки Redis (redis-cli).

    redis-cli
  2. Теперь давайте выполним Lua-скрипт с помощью EVAL. Этот скрипт увеличит счетчик с именем mycounter и вернет увеличенное значение.

    EVAL "local current = redis.call('INCR', KEYS[1]); return current" 1 mycounter

    Давайте разберем эту команду:

    • EVAL "local current = redis.call('INCR', KEYS[1]); return current": Это сам Lua-скрипт. Он использует redis.call('INCR', KEYS[1]) для увеличения значения ключа, указанного в KEYS[1]. Массив KEYS содержит имена ключей, переданные скрипту. Наконец, он возвращает увеличенное значение.
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • mycounter: Это имя ключа, к которому будет обращаться скрипт.

    Вы должны увидеть вывод, подобный этому:

    (integer) 1

    Если вы запустите ту же команду снова, вы увидите увеличение счетчика:

    EVAL "local current = redis.call('INCR', KEYS[1]); return current" 1 mycounter

    Вывод:

    (integer) 2
  3. Давайте проверим значение ключа mycounter с помощью команды GET:

    GET mycounter

    Вывод:

    "2"

    Как видите, Lua-скрипт успешно увеличил счетчик.

  4. Теперь давайте попробуем другой пример. На этот раз мы создадим скрипт, который устанавливает ключ в определенное значение, если он еще не существует.

    EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end" 1 mykey myvalue

    В этой команде:

    • EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end": Это Lua-скрипт. Он проверяет, существует ли ключ KEYS[1]. Если нет, он устанавливает ключ в значение ARGV[1] и возвращает 1. В противном случае он возвращает 0.
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • mykey: Это имя ключа.
    • myvalue: Это значение, которое нужно установить, если ключ не существует.

    Вы должны увидеть вывод, подобный этому:

    (integer) 1

    Это указывает на то, что ключ mykey был установлен в myvalue.

  5. Давайте проверим значение mykey:

    GET mykey

    Вывод:

    "myvalue"

    Если вы запустите команду EVAL снова:

    EVAL "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], ARGV[1]); return 1 else return 0 end" 1 mykey myvalue

    Вывод:

    (integer) 0

    На этот раз скрипт вернул 0, потому что ключ уже существовал.

  6. Выйдите из redis-cli. Это важно для регистрации изменений.

    exit

Передача аргументов в скрипт с помощью EVAL

На предыдущем шаге мы узнали, как выполнять Lua-скрипты с помощью EVAL и получать доступ к ключам. Теперь давайте рассмотрим, как передавать аргументы этим скриптам. Это позволяет создавать более динамичные и многократно используемые скрипты.

Напомним, что команда EVAL принимает следующие аргументы:

  1. Сам Lua-скрипт в виде строки.
  2. Количество ключей, к которым скрипт будет обращаться.
  3. Имена ключей.
  4. Любые дополнительные аргументы, которые вы хотите передать скрипту. Эти аргументы доступны в Lua-скрипте с помощью массива ARGV.

Начнем с примера. Мы создадим Lua-скрипт, который добавляет значение к счетчику Redis. Ключ счетчика и значение для добавления будут переданы в качестве аргументов.

  1. Подключитесь к серверу Redis, используя интерфейс командной строки Redis (redis-cli).

    redis-cli
  2. Теперь давайте выполним Lua-скрипт с помощью EVAL, который увеличивает счетчик на указанную величину.

    EVAL "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current" 1 mycounter 5

    Давайте разберем эту команду:

    • EVAL "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current": Это Lua-скрипт. Он использует redis.call('INCRBY', KEYS[1], ARGV[1]) для увеличения значения ключа, указанного в KEYS[1], на величину, указанную в ARGV[1].
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • mycounter: Это имя ключа, к которому будет обращаться скрипт.
    • 5: Это аргумент, который будет передан скрипту и доступен как ARGV[1].

    Вы должны увидеть вывод, подобный этому (предполагая, что mycounter был равен 2 из предыдущего шага):

    (integer) 7

    Скрипт увеличил ключ mycounter на 5.

  3. Давайте проверим значение ключа mycounter с помощью команды GET:

    GET mycounter

    Вывод:

    "7"
  4. Теперь давайте попробуем другой пример со строковыми аргументами. Мы создадим скрипт, который устанавливает ключ в значение, где и ключ, и значение передаются в качестве аргументов.

    EVAL "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]" 1 mynewkey mynewvalue

    В этой команде:

    • EVAL "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]": Это Lua-скрипт. Он устанавливает ключ KEYS[1] в значение ARGV[1] и возвращает значение.
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • mynewkey: Это имя ключа.
    • mynewvalue: Это значение для установки.

    Вы должны увидеть вывод, подобный этому:

    "mynewvalue"
  5. Давайте проверим значение mynewkey:

    GET mynewkey

    Вывод:

    "mynewvalue"

    Скрипт успешно установил ключ mynewkey в значение mynewvalue.

  6. Вы можете передавать несколько аргументов скрипту. Например, давайте создадим скрипт, который объединяет две строки, переданные в качестве аргументов, и устанавливает результат в ключ.

    EVAL "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result" 1 combinedkey hello world

    В этой команде:

    • EVAL "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result": Это Lua-скрипт. Он объединяет ARGV[1] и ARGV[2] с помощью оператора .., устанавливает ключ KEYS[1] в результат и возвращает результат.
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • combinedkey: Это имя ключа.
    • hello: Это первый строковый аргумент.
    • world: Это второй строковый аргумент.

    Вы должны увидеть вывод, подобный этому:

    "helloworld"
  7. Давайте проверим значение combinedkey:

    GET combinedkey

    Вывод:

    "helloworld"
  8. Выйдите из redis-cli. Это важно для регистрации изменений.

    exit

Загрузка скрипта с помощью SCRIPT LOAD

На предыдущих шагах мы выполняли Lua-скрипты непосредственно с помощью команды EVAL. Хотя это полезно для простых скриптов, это может стать обременительным для более крупных и сложных скриптов. Redis предоставляет команду SCRIPT LOAD для загрузки скриптов в кеш скриптов (script cache) сервера Redis. Это позволяет выполнять скрипт несколько раз без необходимости каждый раз отправлять весь скрипт, что повышает производительность.

Команда SCRIPT LOAD принимает один аргумент: сам Lua-скрипт. Она возвращает SHA1-хеш скрипта, который затем можно использовать для выполнения скрипта с помощью команды EVALSHA (которую мы рассмотрим на следующем шаге).

Давайте посмотрим, как это работает.

  1. Подключитесь к серверу Redis, используя интерфейс командной строки Redis (redis-cli).

    redis-cli
  2. Теперь давайте загрузим Lua-скрипт с помощью SCRIPT LOAD. Мы будем использовать тот же скрипт из предыдущего шага, который увеличивает счетчик на указанную величину.

    SCRIPT LOAD "local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current"

    Эта команда загрузит скрипт в кеш скриптов сервера Redis и вернет SHA1-хеш скрипта. Вы должны увидеть вывод, подобный этому:

    "6b1e8dd2999cb08546e74339c0c9489f9f89a84b"

    Это SHA1-хеш скрипта. Запишите этот хеш, так как он понадобится вам на следующем шаге. Точное значение хеша может отличаться.

  3. Теперь давайте загрузим скрипт, который устанавливает ключ в значение, где и ключ, и значение передаются в качестве аргументов.

    SCRIPT LOAD "redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]"

    Вы должны увидеть вывод, подобный этому:

    "a8b2b3648969459a8198262a9166e945e890987c"

    Опять же, запишите этот хеш.

  4. Давайте загрузим скрипт, который объединяет две строки, переданные в качестве аргументов, и устанавливает результат в ключ.

    SCRIPT LOAD "local result = ARGV[1] .. ARGV[2]; redis.call('SET', KEYS[1], result); return result"

    Вы должны увидеть вывод, подобный этому:

    "d2a800a974ca96849295220424f9a0664a495345"

    Запишите и этот хеш.

  5. Вы можете проверить, загружены ли скрипты, с помощью команды SCRIPT EXISTS. Эта команда принимает один или несколько SHA1-хешей в качестве аргументов и возвращает массив из 0 и 1, где 1 указывает, что скрипт с соответствующим хешем загружен, а 0 указывает, что он не загружен.

    Например, чтобы проверить, загружен ли первый скрипт, который мы загрузили, используйте следующую команду, заменив хеш на тот, который вы получили на шаге 2:

    SCRIPT EXISTS 6b1e8dd2999cb08546e74339c0c9489f9f89a84b

    Вывод:

    1) (integer) 1

    Это указывает на то, что скрипт загружен.

    Если вы попытаетесь проверить скрипт, который не загружен:

    SCRIPT EXISTS 0000000000000000000000000000000000000000

    Вывод:

    1) (integer) 0

    Это указывает на то, что скрипт не загружен.

  6. Выйдите из redis-cli. Это важно для регистрации изменений.

    exit

Запуск загруженного скрипта с помощью EVALSHA

На предыдущем шаге мы узнали, как загружать Lua-скрипты в кеш скриптов (script cache) сервера Redis с помощью команды SCRIPT LOAD. Теперь мы узнаем, как выполнять эти загруженные скрипты с помощью команды EVALSHA.

Команда EVALSHA принимает следующие аргументы:

  1. SHA1-хеш загруженного скрипта.
  2. Количество ключей, к которым скрипт будет обращаться.
  3. Имена ключей.
  4. Любые дополнительные аргументы, которые вы хотите передать скрипту.

Использование EVALSHA более эффективно, чем EVAL, когда вам нужно выполнить один и тот же скрипт несколько раз, поскольку это позволяет избежать отправки всего скрипта на сервер каждый раз.

Давайте посмотрим, как это работает.

  1. Подключитесь к серверу Redis, используя интерфейс командной строки Redis (redis-cli).

    redis-cli
  2. Теперь давайте выполним Lua-скрипт, который увеличивает счетчик на указанную величину, используя EVALSHA. Помните SHA1-хеш, который вы получили на предыдущем шаге для скрипта local current = redis.call('INCRBY', KEYS[1], ARGV[1]); return current? Если нет, вам нужно будет снова загрузить скрипт с помощью SCRIPT LOAD. Для этого примера мы будем считать, что хеш равен 6b1e8dd2999cb08546e74339c0c9489f9f89a84b.

    EVALSHA 6b1e8dd2999cb08546e74339c0c9489f9f89a84b 1 mycounter 5

    Давайте разберем эту команду:

    • EVALSHA 6b1e8dd2999cb08546e74339c0c9489f9f89a84b: Это указывает, что мы хотим выполнить скрипт с SHA1-хешем 6b1e8dd2999cb08546e74339c0c9489f9f89a84b.
    • 1: Это указывает, что скрипт будет обращаться к одному ключу.
    • mycounter: Это имя ключа, к которому будет обращаться скрипт.
    • 5: Это аргумент, который будет передан скрипту и доступен как ARGV[1].

    Вы должны увидеть вывод, подобный этому (предполагая, что mycounter был равен 7 из предыдущего шага):

    (integer) 12

    Скрипт увеличил ключ mycounter на 5.

  3. Давайте проверим значение ключа mycounter с помощью команды GET:

    GET mycounter

    Вывод:

    "12"
  4. Теперь давайте выполним скрипт, который устанавливает ключ в значение, используя EVALSHA. Помните SHA1-хеш, который вы получили на предыдущем шаге для скрипта redis.call('SET', KEYS[1], ARGV[1]); return ARGV[1]? Если нет, вам нужно будет снова загрузить скрипт с помощью SCRIPT LOAD. Для этого примера мы будем считать, что хеш равен a8b2b3648969459a8198262a9166e945e890987c.

    EVALSHA a8b2b3648969459a8198262a9166e945e890987c 1 anotherkey anothervalue

    Вы должны увидеть вывод, подобный этому:

    "anothervalue"
  5. Давайте проверим значение anotherkey:

    GET anotherkey

    Вывод:

    "anothervalue"
  6. Если вы попытаетесь выполнить скрипт с недействительным SHA1-хешем, вы получите ошибку:

    EVALSHA 0000000000000000000000000000000000000000 1 mykey myvalue

    Вывод:

    (error) NOSCRIPT No matching script. Please use EVAL.

    Это указывает на то, что скрипт с указанным SHA1-хешем не загружен.

  7. Выйдите из redis-cli. Это важно для регистрации изменений.

    exit

Резюме

В этой лабораторной работе вы изучили скриптинг Lua в Redis, сосредоточившись на выполнении скриптов непосредственно с помощью команды EVAL. Мы узнали, что EVAL принимает Lua-скрипт в виде строки, количество ключей, к которым осуществляется доступ, и сами имена ключей в качестве аргументов. Мы попрактиковались в увеличении счетчика Redis с помощью Lua-скрипта внутри EVAL, наблюдая, как скрипт получает доступ и изменяет указанный ключ.

Кроме того, мы узнали, как передавать аргументы в Lua-скрипты, загружать скрипты в Redis с помощью SCRIPT LOAD и выполнять загруженные скрипты с помощью EVALSHA. Не забывайте выходить из redis-cli после каждого шага, чтобы ваши команды регистрировались правильно. Это обеспечивает более эффективное выполнение сложных скриптов.