Comments 44
команда EVAL именно интерпретирует строку, т.е. фактически делает то же самое, что и eval во многих скриптовых языках. Однако вы можете сохранять скрипты, и это предполагается делать, если вы используете их в продакшене. Для этого вы должны вызвать SCRIPT LOAD «текст скрипта», он вернёт вам SHA1 строку-хеш, по этому хешу вы потом можете вызвать скрипт, используя EVALSHA %SCRIPT_SHA%, также, как делаете это с EVAL.
Заменить с тем же SHA нельзя, однако можно сбросить скриптовый кеш командой SCRIPT FLUSH, т.е. удалить все скрипты и загрузить заново. Скриптовый кеш живёт до тех пор, пока redis-server не будет перезапущен. Однако это не является большой проблемой, если вы конечно не загружаете скрипты в огромном количестве.
Ну то есть сохранить интерфейс server-side нельзя, это только экономия на размерах вызовов.
Мало того — в случае рестарта сервака их нужно загружать повторно. Напоролся на проде на это :)
Не понимаю, как это возможно. Ведь сначала нужно загрузить скрипт, а уже потом исполнять.
UFO landed and left these words here
Пару месяцев назад пришлось воспользоваться скриптами, чтобы быстро почистить базу от неактуальных данных.

Так вот в lua-скриптах для Redis есть одна недокументированная особенность: там разделено получение данных и их удаление. То есть нельзя в одном скрипте получить список ключей и тут же вызвать их удаление. Redis — это просто не дает сделать. Пришлось писать два скрипта — один формирует список ключей и потом с помощью xargs передаем его второму скрипту для удаления.

В документации указана основная причина использовать скрипты — снижение накладных расходов на пересылку данных и как следствие скорость работы по сравнению с программами обращающимися к редис на прямую.

Для сравнения мной была написанная программа на Go для поиска ключей и удаления. И она выполнялась быстрее lua-скриптов.

Так что мой опыт показывает, что lua-скрипты в Redis есть больше для галочки. Они не оптимизированы для быстрой работы.
UFO landed and left these words here
Я именно что использовал SCAN чтобы найти какие ключи удалить. И после получения списка ключей не мог вызвать HDEL для удаления в этом же скрипте.
UFO landed and left these words here
Нет. У меня была только одна база без слейвов. В ней было 700 млн ключей(примерно 60 Гб), удалил я в итоге 550-570 млн ключей. Версия редиса 2.6.16.
UFO landed and left these words here
UFO landed and left these words here
UFO landed and left these words here
Что касается утечки, то каюсь, не подумал об этом написать, т.к. думал, что это очевидно, ведь это применимо и ко многим sql бд. В частности, если конструировать запросы не через prepare + bind, а в лоб формируя строку запроса, то можно запросто израсходовать лимит дескрипторов в том же oracle, а в дополнение и получить дыру в безопасности, в лице возможности формирования входных данных для sql-инъекции.
Про тип я говорил, как про внутреннее представление данных. То что у нас есть возможность работать со строками как с integer я не отрицаю.
UFO landed and left these words here
P.S. дополню свой комментарий, так как сразу не заметил голосование после статьи. Для программы на Go я тоже использовал 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 в редисе прекрасно позволяет решать огромный спектр вопросов, но это совсем не панацея.
UFO landed and left these words here
Да, вы правы. С какой логикой это сделал Сальваторе понятно и я считаю, что это скорее ограничение корявой реализации репликации/интеграции LUA для части команд. К примеру встроенный генератор случайных числе из самой LUA вам доступен. И часть танцев с бубном вокруг SRANDMEMBER так и работает — получите весь список, кидайте кубик в LUA и формируйте таблицу выдачи. В redis много такого — в конкретной фиче всё супер, но чего-то, самую малость, не хватает.
UFO landed and left these words here
Я понимаю как работает репликация, ровно как и ограничения с этим связанные. Попробуйте посмотреть на это с такой стороны. Сразу после релиза 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 — на все вопросы оставьте хотя бы в конфиге шанс выключить это ответ «Не, а то вдруг что». Только не дали в замен никаких вариантов шарить между скриптами вспомогательные функции (а их, к слову, превиликое множество получается при написании чего-то длиннее пары строчек). Простите, накипело.
UFO landed and left these words here
Поймите, я не хочу сказать, что решения нет. Я хочу сказать, что в соседнем огороде (в том же тарантуле) люди обошлись без костылей. И в редисе могли бы. Проблемы с репликой и LUA были ещё на этапе alpha preview, то, что будут ограничения было понятно ещё до выхода фичи в их стабильную ветку. Я настаиваю на том, что разработчиками стоило бы поправить проблемы в проектировании репликации вместо цикла решений об ограничении функциональности скриптовой части. В любом случае мы с вами про одно и тоже, просто немного с разных сторон.
UFO landed and left these words here
Тарантул вырос как база данных (с транзакциями, репликацией и т.п.), это потом оказалось, что пользователям в Lua-хранимках нужны сокеты, http клиенты и прочее :)
Реплицировать вызовы Lua-функции на slave идеологически не правильно. Подобного рода кактусы уже грызли в MySQL со statement-based replication. В Тарантуле мы реплицируем binary log примитивных запросов (insert, replace, update, delete), поэтому никаких проблем с рандомом и прочим просто не существует. Репликация вообще ничего не знает про Lua, сишные хранимки и т.п., т.к. работает на уровне запросов базы данных.
UFO landed and left these words here
Алексей, советую Вам обратить внимание на Tarantool по следующим причинам:

1. В Tarantool Lua — first class citizen. Есть интерактивная консоль, можно запускать скрипты с #!/usr/bin/tarantool, из Lua кода есть доступ абсолютно ко всем функциям Tarantool. Вкупе это дает более прозрачный и удобный цикл отладки и разработки.

2. Нет проблем с типизацией, т.к. хранилище внутри и так уже использует MsgPack

Кроме того, уже есть множество удобных библиотек, начиная от сокетов, заканчивая http сервером.

// Disclaimer: разработчик Tarantool
Хочу задать косвенный вопрос комментирующим. Кто-нибудь смотрел на замену Redis в виде SSDB и Ledis? (Обертки над различными базами, например leveldb, понимающие на 90% протокол Redis) Когда редисом хочется пользоваться, но память на сервере не позволяет.

Есть какие-то впечатления по ним из опыта?
я использовал SSDB полтора года на продакшине, где-то 4 миллиарда ключей, 38Гб места, скорость была очень хорошей. Проблему создавало только обслуживание, например compact на такой базе требовал х2 места. В остальном вроде никаких проблем не было
Only those users with full accounts are able to leave comments. Log in, please.