EVAL и EVALSHA
Тема дорожной карты · Redis
EVAL выполняет Lua-скрипт атомарно на сервере Redis, принимая в качестве параметров исходный текст скрипта, количество ключей, сами ключи и дополнительные аргументы. Поскольку EVAL передаёт полный текст скрипта при каждом вызове, Redis предоставляет EVALSHA для выполнения ранее загруженного скрипта по его SHA1-дайджесту, снижая сетевые накладные расходы для часто используемых скриптов. Скрипты загружаются командой SCRIPT LOAD, возвращающей SHA1-хэш, который затем используется в EVALSHA. Lua-скрипты в Redis выполняются атомарно — никакие другие команды не выполняются во время работы скрипта, — что делает EVAL идеальным для реализации паттернов сравнения-и-замены (compare-and-swap) или многоключевых транзакций, охватывающих несколько структур данных. Функция redis.call() внутри Lua вызывает ошибку при сбое команды, а redis.pcall() возвращает объекты ошибок для аккуратной обработки.
Как это работает
EVAL и EVALSHA имеет два инструмента атомарности. MULTI/EXEC ставит команды в очередь; они выполняются как один блок — но нет rollback (Redis не ACID-D, изоляции тоже нет, если читаете между командами). WATCH добавляет optimistic locking — EXEC валится, если watched-ключ изменился. EVAL / EVALSHA исполняет Lua-скрипты атомарно на сервере; скрипт — одна неделимая операция. Lua — правильный инструмент для compound read+write, которые должны быть атомарными.
Когда применять
MULTI/EXEC — для "выполнить эти N команд как единицу без других команд между". WATCH + MULTI/EXEC — для compare-and-swap. Lua (EVAL) — для сложной атомарной логики (rate limiter, debounce, distributed semaphore). Всегда кешируйте SHA (EVALSHA) вместо повторной отправки тела скрипта — экономит bandwidth и парсинг.
Типичные ошибки
Ловушки EVAL и EVALSHA: расчёт, что MULTI/EXEC — транзакция в SQL-смысле (нет — без rollback); долгие Lua-скрипты блокируют однопоточный сервер (всё ждёт EXEC); не обрабатывают nil от EXEC (WATCH-конфликт — retry); Lua-код, мутирующий ключ на основе текущего значения без WATCH (race condition при разделении на команды).