Pull to refresh

JavaScript триггеры и функции появились в Redis 7.2

Level of difficultyEasy
Reading time6 min
Views2.6K
Original author: Thomas Caudron and Pieter Cailliau

Как правило, приложения обрабатывают операции бизнес-логики, отправляя код для выполнения в базу данных. Это медленный процесс, поскольку код передается от клиента на сервер каждый раз, когда выполняется функция. Код, который используется для работы с одной и той же базой данных, может повторятся в разных приложениях, соответственно разработчик несет ответственность за поддержание согласованности этого кода в независимости от того, выполняет ли код простые запросы или сложные операции с данными.

Следуя манифесту Redis «Мы против сложности», нам пришлось принять меры и найти решение этих проблем.

Четыре года назад мы представили RedisGears, нашу первую модель программирования на платформе. Разработчики писали и выполняли скрипты в непосредственной близости от данных. Однако скрипты были эфемерными и предоставлялись каждым клиентом по отдельности, что могло привести к неконсистентности.

Следуя этому направлению, в Redis 7.0 мы представили первоначальную реализацию поддержки скриптов с функциями . Функции повысили удобство использования и надежность, поскольку они являются частью базы данных и в их отношении работает репликация и надежная запись на диск.

И теперь мы с гордостью представляем следующий шаг. В Redis 7.2 мы представили триггеры и функции . Они улучшают программируемость Redis, расширяют возможности серверной части, улучшают способ и время выполнения функций в базе данных и облегчают выполнение сложной бизнес-логики непосредственно там, где находятся данные.

Основы триггеров и функций

Триггеры и функции — это новое поколение возможностей программирования, доступное через Redis Stack. Они позволяет разработчикам программировать, хранить и автоматически выполнять код JavaScript при изменении данных непосредственно в базе данных Redis.

Эта возможность позволяет разработчикам определять события (триггеры) для выполнения функций в непосредственной близости с данными. То есть разработчики определяют бизнес-логику, которая выполняется в ответ на события или команды базы данных. Это ускоряет код и взаимодействие, поскольку не нужно ждать, пока код от клиентов будет перенесен в базу данных.

Это также ускоряет время реакции на другие события в Redis, такие как уведомления пространства ключей (keyspace notifications), которые не обрабатываются в реальном времени другими средствами, такими как события публикации и подписки (Pub/Sub).

Так же триггеры и функции контролируют распределение внутри кластерной базы данных, устанавливая библиотеки на каждый сегмент и выполняя функции в зависимости от того, где находится ключ.

Мы также ввели удаленные функции (remote functions). Удаленные функции позволяют выполнять чтения на любом слоте, даже в кластерной базе данных, поэтому все ваши данные доступны из каждой функции.

Используем JavaScript, самый популярный язык программирования

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 в телеграме про разработку и не только ;-)

Tags:
Hubs:
Total votes 6: ↑6 and ↓0+6
Comments0

Articles