Redis позволяет загружать сценарии Lua с помощью команды SCRIPT LOAD
, а в документации говорит, что возвращенный "хэш SHA-1" может быть вызван через EVALSHA
. Это работает, как и ожидалось.
Затем я «оптимизировал» часть процесса развертывания, так что у нас есть отдельная программа, которая загружает сценарии Lua. Он генерирует хэши SHA-1 с помощью команды Unix sha1sum
, поскольку я (наивно) предположил, что Redis фактически использовал SHA-1 файла, как указано. Но после этого я продолжал получать NOSCRIPT
ошибок при попытке EVAL
скриптов в Redis.
Очевидно, Redis (я использую v3.0.6) изменяет скрипт перед генерацией хэша SHA-1 (демонстрация ниже).
Перейдя к самому простому тестовому примеру, я начал с этого сценария:
test.lua:
return nil
Я убедился, что файл сценария соответствует тому, что я думаю, и что оболочка (Bash) ничего странного с ним не сделала:
$ hexdump -C test.lua
00000000 72 65 74 75 72 6e 20 6e 69 6c 0a |return nil.|
0000000b
$ sha1sum test.lua
6f65c1b09395aee959e644fa26d4c6ca6f0d462d test.lua
$ echo "$(cat test.lua)" | sha1sum
6f65c1b09395aee959e644fa26d4c6ca6f0d462d -
И чтобы быть уверенным, я сравнил хеш SHA-1 с онлайн-реализацией SHA-1 на JavaScript:
6F65C1B09395AEE959E644FA26D4C6CA6F0D462D
Итак, я загрузил его в Redis:
$ redis-cli SCRIPT LOAD "$(cat test.lua)"
"79cefb99366d8809d2e903c5f36f50c2b731913f"
В попытке угадать, что Redis может делать со сценарием, я также попробовал тот же сценарий с CRLF в стиле Windows вместо LF-строк в стиле Unix, но это также не соответствовало результату Redis:
$ hexdump -C test.lua
00000000 72 65 74 75 72 6e 20 6e 69 6c 0d 0a |return nil..|
0000000c
$ sha1sum test.lua
98260fd830c34607e437f5e418683c2a644b0d82 test.lua
Наконец, в раздражении я попытался удалить все пустое пространство, и вот! и вот, результаты совпали.
Пройдя немного дальше, я обнаружил, что по какой-то причине завершающие пробельные символы в последней строке удаляются с помощью Redis !
В качестве доказательства приведенный ниже пример работает либо с LF, либо с CRLF, внутренне, но завершается неудачно, если вы добавляете LF или CRLF в последнюю строку:
$ hexdump -C test.lua
00000000 69 66 20 74 72 75 65 20 74 68 65 6e 0a 72 65 74 |if true then.ret|
00000010 75 72 6e 20 6e 69 6c 0a 65 6e 64 |urn nil.end|
0000001b
$ sha1sum test.lua
ee9d1de0dae159d76a57ecb8e7e8c8c75283ef1d test.lua
$ redis-cli SCRIPT LOAD "$(cat test.lua)"
ee9d1de0dae159d76a57ecb8e7e8c8c75283ef1d
Так что дает? Почему Redis изменяет последнюю строку файла сценария перед вычислением хэша файла?
Редактировать: Решение, любезно предоставленное mwp , Итамар Хабер и проблема GitHub :
По-видимому, это проблема Bash, которая может иметь какое-то отношение к таинственной переменной оболочки IFS
, хотя, похоже, затрагивается только trailing-newline.
Не используйте "$(...)"
для загрузки скрипта, хотя StackOverflow рекомендует использовать форму .
Используйте redis-cli -x SCRIPT LOAD < script.lua
, который направляет файл через stdin
к redis-cli
, избегая мутаций. Флаг -x
указывает redis-cli
прочитать следующий аргумент из stdin
.