Как стать автором
Обновить

Комментарии 44

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

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

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

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

Так что мой опыт показывает, что lua-скрипты в Redis есть больше для галочки. Они не оптимизированы для быстрой работы.
НЛО прилетело и опубликовало эту надпись здесь
Я именно что использовал SCAN чтобы найти какие ключи удалить. И после получения списка ключей не мог вызвать HDEL для удаления в этом же скрипте.
НЛО прилетело и опубликовало эту надпись здесь
Нет. У меня была только одна база без слейвов. В ней было 700 млн ключей(примерно 60 Гб), удалил я в итоге 550-570 млн ключей. Версия редиса 2.6.16.
НЛО прилетело и опубликовало эту надпись здесь
Вы целое мини-исследование провели :-)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Что касается утечки, то каюсь, не подумал об этом написать, т.к. думал, что это очевидно, ведь это применимо и ко многим sql бд. В частности, если конструировать запросы не через prepare + bind, а в лоб формируя строку запроса, то можно запросто израсходовать лимит дескрипторов в том же oracle, а в дополнение и получить дыру в безопасности, в лице возможности формирования входных данных для sql-инъекции.
Про тип я говорил, как про внутреннее представление данных. То что у нас есть возможность работать со строками как с integer я не отрицаю.
НЛО прилетело и опубликовало эту надпись здесь
P.S. дополню свой комментарий, так как сразу не заметил голосование после статьи. Для программы на Go я тоже использовал radix.v2.

Но где-то недавно была информация что библиотека Redigo быстрее чем radix.v2. Так что может быть можно написать еще более быстрый скрипт для чистки базы, чем получилось у меня.
Я использую а продакшине Redigo. Доволен очень. Удобный api даже смог красиво прикрутить newrelic на запросы в редис. Одно плохо есть проблема писать struct которые не только string а потом их читать надо их переводит в json а потом обратно. Немножко накдладно было. заменил json на messagepack с статической серилизацией получилось очень быстрая вещь
Я не в рамках этой программы сначала использовал для подключения к редис gopkg.in/redis.v3, но этот оказалось полное извращение. (Отдельная функция для каждой команды редис. Причем каждая возвращает свой набор параметров.) Уже потом увидел более-менее сносный radix.v2 По поводу Redigo — его еще не смотрел, только читал, что он быстрее.
redigo все проще
data, err := c.Do(command, args...)

Насколько мне известно, у скриптов в redis одна основная задача, сократить все обращения к базе до одного round-trip при этом обеспечить атомарность. Действительно странно, что у вас получалось достичь большей скорости на go. Ваша программа на go последовательно вызывала комманды или же вы делали через транзакции multi
Использовал pipelining
Важно ещё помнить про то, что в 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-хранимках нужны сокеты, http клиенты и прочее :)
Реплицировать вызовы Lua-функции на slave идеологически не правильно. Подобного рода кактусы уже грызли в MySQL со statement-based replication. В Тарантуле мы реплицируем binary log примитивных запросов (insert, replace, update, delete), поэтому никаких проблем с рандомом и прочим просто не существует. Репликация вообще ничего не знает про Lua, сишные хранимки и т.п., т.к. работает на уровне запросов базы данных.
НЛО прилетело и опубликовало эту надпись здесь
Дикий ад, не проще ли Tarantool поставить и не мучить себя?
Алексей, советую Вам обратить внимание на 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 места. В остальном вроде никаких проблем не было
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации