JavaScript триггеры и функции появились в Redis 7.2
- понедельник, 18 сентября 2023 г. в 00:00:20
Как правило, приложения обрабатывают операции бизнес-логики, отправляя код для выполнения в базу данных. Это медленный процесс, поскольку код передается от клиента на сервер каждый раз, когда выполняется функция. Код, который используется для работы с одной и той же базой данных, может повторятся в разных приложениях, соответственно разработчик несет ответственность за поддержание согласованности этого кода в независимости от того, выполняет ли код простые запросы или сложные операции с данными.
Следуя манифесту Redis «Мы против сложности», нам пришлось принять меры и найти решение этих проблем.
Четыре года назад мы представили RedisGears, нашу первую модель программирования на платформе. Разработчики писали и выполняли скрипты в непосредственной близости от данных. Однако скрипты были эфемерными и предоставлялись каждым клиентом по отдельности, что могло привести к неконсистентности.
Следуя этому направлению, в Redis 7.0 мы представили первоначальную реализацию поддержки скриптов с функциями . Функции повысили удобство использования и надежность, поскольку они являются частью базы данных и в их отношении работает репликация и надежная запись на диск.
И теперь мы с гордостью представляем следующий шаг. В Redis 7.2 мы представили триггеры и функции . Они улучшают программируемость Redis, расширяют возможности серверной части, улучшают способ и время выполнения функций в базе данных и облегчают выполнение сложной бизнес-логики непосредственно там, где находятся данные.
Триггеры и функции — это новое поколение возможностей программирования, доступное через Redis Stack. Они позволяет разработчикам программировать, хранить и автоматически выполнять код JavaScript при изменении данных непосредственно в базе данных Redis.
Эта возможность позволяет разработчикам определять события (триггеры) для выполнения функций в непосредственной близости с данными. То есть разработчики определяют бизнес-логику, которая выполняется в ответ на события или команды базы данных. Это ускоряет код и взаимодействие, поскольку не нужно ждать, пока код от клиентов будет перенесен в базу данных.
Это также ускоряет время реакции на другие события в Redis, такие как уведомления пространства ключей (keyspace notifications), которые не обрабатываются в реальном времени другими средствами, такими как события публикации и подписки (Pub/Sub).
Так же триггеры и функции контролируют распределение внутри кластерной базы данных, устанавливая библиотеки на каждый сегмент и выполняя функции в зависимости от того, где находится ключ.
Мы также ввели удаленные функции (remote functions). Удаленные функции позволяют выполнять чтения на любом слоте, даже в кластерной базе данных, поэтому все ваши данные доступны из каждой функции.
Redis использует Lua для сценариев и функций. У Lua есть много преимуществ , таких как возможность повторного использования кода, но он не является широко используемым языком среди профессиональных разработчиков. Согласно опросу разработчиков StackOverflow 2022 года , только 3,2% разработчиков используют Lua профессионально.
Напротив, две трети разработчиков используют JavaScript. Использование известного языка снижает барьер входа для новых разработчиков Redis. Не нужно учить еще один язык.
Еще одним преимуществом триггеров и функций является то, что они уменьшают сложность управления бизнес-логикой в нескольких приложениях одновременно.
Когда несколько приложений обращаются к одной и той же базе данных, разработчикам приходится координировать, как приложения последовательно обрабатывают данные. Обычно код дублируется в каждом приложении для валидации данных, улучшения результатов поиска или обновления базы данных, когда другое приложение вносит изменения.
Благодаря триггерам и функциям больше нет необходимости дублировать код в нескольких приложениях. Код всегда выполняется одинаково: после ручного вызова или в качестве реакции на событие в базе данных.
До сих пор реакция на события базы данных в Redis требовала от разработчиков использования механизма Pub/Sub. Хотя Pub/Sub имеет множество преимуществ, это не всегда правильный выбор. В частности, Pub/Sub не работает в режиме реального времени. Клиент должен иметь активную подписку на события; если клиент не слушает, события теряются.
Теперь разработчики могут регистрировать триггеры пространства ключей, которые выполняются на основе префикса ключа и типа события. Триггер выполняется атомарным образом, соответственно стороннее событие не будет обработано между оригинальным событием и вашей бизнес-логикой.
Всегда легче понять ситуацию на практическом примере. Здесь мы представляем регистрацию функции и триггера. Функция выполняется, когда она вызывается с помощью команды TFCALL
; триггер выполняется на основе событий в Redis.
В прологе указано, что мы используем движок js, имя библиотеки — lib, а минимально необходимый API триггеров и функций — версия 1.0.
#!js name=lib api_version=1.0
Далее мы создаем функцию, которая возвращает результат команды Redis. Аргумент client
предоставляет доступ для выполнения команд. А аргумент data
содержит ключи и другие аргументы, с которыми может быть вызвана функция.
function answer(client, data) {
return client.call('ping');
}
Глобальная переменная redis
позволяет регистрировать триггеры и функции, а также логгировать что-либо. При регистрации мы назначаем функции имя, с которым сможем ее вызвать впоследствии:
redis.registerFunction('playPingPong', answer);
Полый JavaScript файл выглядит следующим образом (сохраним его как lib.js
):
#!js name=lib api_version=1.0
function answer(client, data) {
return client.call('ping')
}
redis.registerFunction('playPingPong', answer);
Затем мы загружаем нашу функцию в Redis с помощью команды TFUNCTION LOAD
(это так же распространяет написанную библиотеку по всему кластеру).
> redis-cli -x TFUNCTION LOAD < ./lib.js
"OK"
Теперь мы можем вызвать функцию с помощью команды TFCALL
. Полное имя функции состоит из имени библиотеки и имени функции через точку:
> redis-cli TFCALL lib.playPingPong 0
"PONG"
Тем самым мы успешно создали, зарегистрировали и запустили функцию в базе данных Redis.
Мы можем расширить этот пример с помощью триггера пространства ключей. Мы добавляем триггер, который реагирует на ключи с префиксом fellowship:
. Добавьте этот код в конец файла lib.js
:
function addLastUpdatedField(client, data) {
if (data.event == 'hset') {
var currentDateTime = Date.now();
client.call('hset', data.key, 'last_updated', currentDateTime.toString());
}
}
redis.registerKeySpaceTrigger(
'addLastUpdated',
'fellowship:',
addLastUpdatedField
);
Для обновления существующей библиотеки нужно воспользоваться командой TFUNCTION LOAD
с аргументом REPLACE
. После выполнения обновленная версия библиотеки станет доступна всем клиентам Redis, и они начнут использовать новую бизнес-логику:
> redis-cli -x TFUNCTION LOAD REPLACE < ./lib.js
"OK"
Чтобы протестировать новый триггер пространства ключей, создайте новый ключ, начиная с felowship:
и проверьте поля с помощью RedisInsight. Триггер пространства ключей выполняется непосредственно во время добавления новой записи, поэтому поле last_updated уже присутствует сразу после создания ключа.
Присоединяйтесь к общедоступной предварительной версии триггеров и функций с помощью Redis Stack 7.2. Можно начать работать с Redis Stack в облаке, создав базу данных Redis Enterprise Cloud с использованием fixed tier в Google Cloud/Asia Pacific (Tokyo) или AWS/Asia Pacific (Singapore) или разверните экземпляр самостоятельно с помощью центра загрузки.
Стабильная версия триггеров и функций запланирована на релиз Redis 8. Она будет включать в себя фидбек, полученный от пользователей предварительной версии, а также дополнительные функции, такие как временные триггеры и дополнительные возможности по отладке.
Комментарии и отзывы приветствуются в списке рассылки Redis.
От переводчика.
В оригинальной статье некоторые технические моменты опущены, без которых создается ощущение недосказанности. Давайте восполним:
Официальная документация - тут.
Под капотом JavaScript в Redis использует всеми известный V8 (читайте в релизе RedisGears от 20 июня). Версия v8 свеженькая 11+, так что все прелести современного js доступны.
Команда Redis старается продвигать облачные Redis Stack и Redis Enterprise всеми силами, но это необязательно. Проще всего попробовать с помощью докер docker run -it --rm redis/redis-stack-server:7.2.0-v2
. Или упражняться с установкой RedisGears последней версии с поддержкой JavaScript на голый Redis. Последний докер от RedisGears у меня на Mac работать не хочет (видимо сказывает тот факт, что нет билда под arm64). В любое случае ссылочки по RedisGears тут: докер redislabs/redisgears и сборка из исходников (кстати, написан на Rust).
Программировать либы на JS под Redis можно не только для себя любимого, а в опенсорс (проигрыш по с скорости с сишными модулями оставим за скобками). Здесь встает вопрос конфигурирования такого модуля и у команды Redis уже есть готовый ответ на это - Triggers and functions / Concepts / Library configuration.
Спасибо за внимание!
Веду канал Alex Code в телеграме про разработку и не только ;-)