Комментарии 44
Таки они хронятся в redis, или только исполняются?
команда EVAL именно интерпретирует строку, т.е. фактически делает то же самое, что и eval во многих скриптовых языках. Однако вы можете сохранять скрипты, и это предполагается делать, если вы используете их в продакшене. Для этого вы должны вызвать SCRIPT LOAD «текст скрипта», он вернёт вам SHA1 строку-хеш, по этому хешу вы потом можете вызвать скрипт, используя EVALSHA %SCRIPT_SHA%, также, как делаете это с EVAL.
То есть «заменить» скрипт нельзя?
Заменить с тем же SHA нельзя, однако можно сбросить скриптовый кеш командой SCRIPT FLUSH, т.е. удалить все скрипты и загрузить заново. Скриптовый кеш живёт до тех пор, пока redis-server не будет перезапущен. Однако это не является большой проблемой, если вы конечно не загружаете скрипты в огромном количестве.
p.s.: вот если бы EVALSHA работало без SCRIPT LOAD!!!
Пару месяцев назад пришлось воспользоваться скриптами, чтобы быстро почистить базу от неактуальных данных.
Так вот в lua-скриптах для Redis есть одна недокументированная особенность: там разделено получение данных и их удаление. То есть нельзя в одном скрипте получить список ключей и тут же вызвать их удаление. Redis — это просто не дает сделать. Пришлось писать два скрипта — один формирует список ключей и потом с помощью xargs передаем его второму скрипту для удаления.
В документации указана основная причина использовать скрипты — снижение накладных расходов на пересылку данных и как следствие скорость работы по сравнению с программами обращающимися к редис на прямую.
Для сравнения мной была написанная программа на Go для поиска ключей и удаления. И она выполнялась быстрее lua-скриптов.
Так что мой опыт показывает, что lua-скрипты в Redis есть больше для галочки. Они не оптимизированы для быстрой работы.
Так вот в lua-скриптах для Redis есть одна недокументированная особенность: там разделено получение данных и их удаление. То есть нельзя в одном скрипте получить список ключей и тут же вызвать их удаление. Redis — это просто не дает сделать. Пришлось писать два скрипта — один формирует список ключей и потом с помощью xargs передаем его второму скрипту для удаления.
В документации указана основная причина использовать скрипты — снижение накладных расходов на пересылку данных и как следствие скорость работы по сравнению с программами обращающимися к редис на прямую.
Для сравнения мной была написанная программа на Go для поиска ключей и удаления. И она выполнялась быстрее lua-скриптов.
Так что мой опыт показывает, что lua-скрипты в Redis есть больше для галочки. Они не оптимизированы для быстрой работы.
Я именно что использовал SCAN чтобы найти какие ключи удалить. И после получения списка ключей не мог вызвать HDEL для удаления в этом же скрипте.
Что касается утечки, то каюсь, не подумал об этом написать, т.к. думал, что это очевидно, ведь это применимо и ко многим sql бд. В частности, если конструировать запросы не через prepare + bind, а в лоб формируя строку запроса, то можно запросто израсходовать лимит дескрипторов в том же oracle, а в дополнение и получить дыру в безопасности, в лице возможности формирования входных данных для sql-инъекции.
Про тип я говорил, как про внутреннее представление данных. То что у нас есть возможность работать со строками как с integer я не отрицаю.
P.S. дополню свой комментарий, так как сразу не заметил голосование после статьи. Для программы на Go я тоже использовал radix.v2.
Но где-то недавно была информация что библиотека Redigo быстрее чем radix.v2. Так что может быть можно написать еще более быстрый скрипт для чистки базы, чем получилось у меня.
Но где-то недавно была информация что библиотека Redigo быстрее чем radix.v2. Так что может быть можно написать еще более быстрый скрипт для чистки базы, чем получилось у меня.
Я использую а продакшине Redigo. Доволен очень. Удобный api даже смог красиво прикрутить newrelic на запросы в редис. Одно плохо есть проблема писать struct которые не только string а потом их читать надо их переводит в json а потом обратно. Немножко накдладно было. заменил json на messagepack с статической серилизацией получилось очень быстрая вещь
Я не в рамках этой программы сначала использовал для подключения к редис gopkg.in/redis.v3, но этот оказалось полное извращение. (Отдельная функция для каждой команды редис. Причем каждая возвращает свой набор параметров.) Уже потом увидел более-менее сносный radix.v2 По поводу Redigo — его еще не смотрел, только читал, что он быстрее.
Насколько мне известно, у скриптов в redis одна основная задача, сократить все обращения к базе до одного round-trip при этом обеспечить атомарность. Действительно странно, что у вас получалось достичь большей скорости на go. Ваша программа на go последовательно вызывала комманды или же вы делали через транзакции multi
Важно ещё помнить про то, что в Lua у вас есть доступ не ко всем функциям редиса. К примеру нельзя использовать SRANDMEMBER, что фактически не позволит вам писать процедуры с логикой «Вернуть N случайных значений из SET» или семейство SCAN функций. Т.е. скажем сделать какой-то аналог «воркера», который выполнит операцию над семейством ключей или полей в LUA не выйдет. Помните, что у вас не будет человеческой отладки, если вы решили писать что-то действительно сложное, что до сих пор нет нормальных библиотек для тестирования LUA процедур. Насколько я знаю ни на одном языке (хорошая идея для проекта на гитхаб). Это совсем не обычная ситуацию, но помните про ограничение с LUAI_MAXCSTACK. Помните, что любые битовые операции в LUA удивят вас тем, что при поддержки 64 битных целых чисел все битовые операции ограничены 32 битными со знаком. Помните, что фактически у вас нет скриптов, если вы используете кластер, т.к. нет авто переадресации запросов на соседние ноды. LUA в редисе прекрасно позволяет решать огромный спектр вопросов, но это совсем не панацея.
Да, вы правы. С какой логикой это сделал Сальваторе понятно и я считаю, что это скорее ограничение корявой реализации репликации/интеграции LUA для части команд. К примеру встроенный генератор случайных числе из самой LUA вам доступен. И часть танцев с бубном вокруг SRANDMEMBER так и работает — получите весь список, кидайте кубик в LUA и формируйте таблицу выдачи. В redis много такого — в конкретной фиче всё супер, но чего-то, самую малость, не хватает.
Я понимаю как работает репликация, ровно как и ограничения с этим связанные. Попробуйте посмотреть на это с такой стороны. Сразу после релиза 2.6 (в котором добавили LUA) сразу же подняли вопрос и про RANDOMKEY и про SRANDMEMBER. Это весьма логично, т.к. сама структура SET подразумевает, что вам для широкого спектра бизнес задач нужно получать из неё N случайных элементов (не даром в 2.6 в эту функцию добавили второй аргумент — количество случайных элементов). Когда впервые поднимался этот вопрос Сальваторе предлагали альтернативу с тем, чтобы переписать репликацию для SET с тем, чтобы свести внутреннюю структуру SET на слейве и мастере — тогда возможно было бы обращаться к элементам сета по индексам. Он ответил в духе — «Это не возможно». К чему я так цепляюсь к этому случае — в редис почти всё так. Смотрите, я отвечаю (и читаю) вопросы по редису на stackoverflow. Аудитория продукта (а редис продукт, который Сальваторе продаёт) часто задаёт вопросы, ответ на который — используйте уникальный список с произвольным доступом. Т.е. или в LIST возможность взять индекс по значению (LRANK request) или в SET получить аналог LRANGE (простите на память не помню как назывался тикет на гитхабе). И тогда можно на LUA можно эффективно решать этот класс задач. И на оба вопроса ответ — «Напишите как нить сами на LUA». Это, имхо, вопрос отношения показывающий отношения основного мейнтейнера в своему продукту. К слову, в том же Tarantool Костя Осипов с командой идёт от решения конкретных проблем и кейсов своих пользователей, вместо отсылок в случае редиса. Как и в 2.8 (поправьте если путаю) вхерачили Global variables protection в LUA — на все вопросы оставьте хотя бы в конфиге шанс выключить это ответ «Не, а то вдруг что». Только не дали в замен никаких вариантов шарить между скриптами вспомогательные функции (а их, к слову, превиликое множество получается при написании чего-то длиннее пары строчек). Простите, накипело.
Поймите, я не хочу сказать, что решения нет. Я хочу сказать, что в соседнем огороде (в том же тарантуле) люди обошлись без костылей. И в редисе могли бы. Проблемы с репликой и LUA были ещё на этапе alpha preview, то, что будут ограничения было понятно ещё до выхода фичи в их стабильную ветку. Я настаиваю на том, что разработчиками стоило бы поправить проблемы в проектировании репликации вместо цикла решений об ограничении функциональности скриптовой части. В любом случае мы с вами про одно и тоже, просто немного с разных сторон.
Реплицировать вызовы Lua-функции на slave идеологически не правильно. Подобного рода кактусы уже грызли в MySQL со statement-based replication. В Тарантуле мы реплицируем binary log примитивных запросов (insert, replace, update, delete), поэтому никаких проблем с рандомом и прочим просто не существует. Репликация вообще ничего не знает про Lua, сишные хранимки и т.п., т.к. работает на уровне запросов базы данных.
Алексей, советую Вам обратить внимание на Tarantool по следующим причинам:
1. В Tarantool Lua — first class citizen. Есть интерактивная консоль, можно запускать скрипты с #!/usr/bin/tarantool, из Lua кода есть доступ абсолютно ко всем функциям Tarantool. Вкупе это дает более прозрачный и удобный цикл отладки и разработки.
2. Нет проблем с типизацией, т.к. хранилище внутри и так уже использует MsgPack
Кроме того, уже есть множество удобных библиотек, начиная от сокетов, заканчивая http сервером.
// Disclaimer: разработчик Tarantool
1. В Tarantool Lua — first class citizen. Есть интерактивная консоль, можно запускать скрипты с #!/usr/bin/tarantool, из Lua кода есть доступ абсолютно ко всем функциям Tarantool. Вкупе это дает более прозрачный и удобный цикл отладки и разработки.
2. Нет проблем с типизацией, т.к. хранилище внутри и так уже использует MsgPack
Кроме того, уже есть множество удобных библиотек, начиная от сокетов, заканчивая http сервером.
// Disclaimer: разработчик Tarantool
Хочу задать косвенный вопрос комментирующим. Кто-нибудь смотрел на замену Redis в виде SSDB и Ledis? (Обертки над различными базами, например leveldb, понимающие на 90% протокол Redis) Когда редисом хочется пользоваться, но память на сервере не позволяет.
Есть какие-то впечатления по ним из опыта?
Есть какие-то впечатления по ним из опыта?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
«Хранимые процедуры» в Redis