Академический Документы
Профессиональный Документы
Культура Документы
Редактирование статьи
EugeneUshakov 15 марта в 00:34
Использование Redis почти как SQL БД:
Реализация чата с кешированием сообщений
Начту с описания проблемы.
Допустим, вы хотите создать чат и хранить сообщения для него.
Вполне возможно, вы можете добавить для этого простую базу
данных (БД), такую как MySQL или даже NoSQL.
Однако постоянно извлекать сообщения из БД может быть накладно и
долго. Особенно, если в чате есть большое количество
неавторизованных пользователей или пользователей
с определенными ролями, для которых так же, как и
для неавторизованных, нежелательно расходовать ресурсы БД
сервера. Кроме того, логично кешировать все сообщения
пользователей в чате, где‑то помимо основной базы данных, так
как это самая востребованная для получения информация. Логично
использовать Redis для кеширования. Мне понравилось видео,
которое за 100 секунд объясняет, что такое Redis — Redis in
100 Seconds.
Обычно многие используют Redis как key‑value (dictionary) хранилище.
Кстати, видео вскользь объясняет, что Redis — это несколько большее,
чем key‑value, как многие привыкли думать.
https://habr.com/ru/article/edit/800379/ 1/14
10.04.2024, 22:15 Редактирование статьи / Хабр
Подпись к изображению
Задача у нас несколько сложнее, не просто достать сообщения
из Redis по ключу, как обычно. Мы еще хотим и доставать сообщения
разными гибкими настраиваемыми и кастомными запросами,
в зависимости от разных входящих параметров и условий,
фильтровать и сортировать... В общем, сделать запросы к Redis почти
так же, как мы привыкли взаимодействовать с SQL БД. Логично
продублировать работу MySQL сервера для функционала выше и
добавить Redis как кэш для сообщений в чате.
Только есть проблема: Redis — NoSQL кэш БД и с довольно
урезанным функционалом.
Вы скажете... Мы же можем достать сообщения и их уже
отфильтровать на стороне сервера в коде по любой нужной логике. А
если сообщений десятки или сотни тысяч?! Это крайне
неэффективно.
Гораздо эффективнее было бы уже при запросе к Redis делать так,
чтобы он фильтровал, сортировал и выдавал результат, как обычная
SQL БД.
Удивлены или сомневаетесь, что такое возможно? Возможно!
Добро пожаловать под кат!
https://habr.com/ru/article/edit/800379/ 2/14
10.04.2024, 22:15 Редактирование статьи / Хабр
Подпись к изображению
Но... Давайте сначала все равно посмотрим на более полное
описание задачи.
При каждой отправке логично отсылать и доставлять сообщение
адресатам, например, по веб‑сокету. Также заносить это сообщение
в базу данных, чтобы всё это где‑то хранилось. Этого кода не будет
в примере, но это важно для общего понимания.
Мы намереваемся разработать на сервере API, которое
по нескольким разным входным параметрам выдает разный
результат. Если нужно, оно обратится в реальную БД MySQL, а если
надо — в кеш в Redis, имитируя Where-подобные запросы,
как для SQL. При этом мы избежим перебора, при котором сложность
может быть O(n), чего бы очень не хотелось.
К счастью, в Redis есть дополнительный модуль для этого —
RediSearch. Изначально он нужен для полнотекстового поиска.
Но обо всем по порядку.
https://habr.com/ru/article/edit/800379/ 3/14
Поехали...
10.04.2024, 22:15 Редактирование статьи / Хабр
Объясню неочевидное.
Строка 8. Если onlyOwn == true, то этот параметр имеет более
высокий приоритет над остальными для выборки, и сообщения
для себя надо достать в первую очередь.
Строка 15. Формируем объект searchCriteria, на основе которого
вырастет дальнейший запрос для SQL и Redis.
https://habr.com/ru/article/edit/800379/ 5/14
Прежде чем перейдем непосредственно к получению сообщений, я
10.04.2024, 22:15 Редактирование статьи / Хабр
Подпись к изображению
Данные достаются по индексу, возможна высокооптимизированная
выдача и никаких O(n):) А при определенных форматах структур
данных для поиска (в том числе и наш случай) и шаблона для scan
нельзя гарантировать, что удастся избежать перебора.
Теперь настроим RediSearch так, чтоб он справлялся с запросом,
который мы сформировали выше. Сначала надо в RediSearch создать
индекс для поиска на нужные поля и их типы командой FT.CREATE.
1 const { SchemaFieldTypes } = require('redis');
2
3 static async initialize() {
4 await redisClient.connect();
5 try {
https://habr.com/ru/article/edit/800379/ 6/14
10.04.2024, 22:15 Редактирование статьи / Хабр
6 await redisClient.ft.create('idx:messages', {
7 userId: SchemaFieldTypes.NUMERIC,
8 chatId: SchemaFieldTypes.NUMERIC,
9 userId: SchemaFieldTypes.NUMERIC,
10 message: SchemaFieldTypes.TEXT,
11 ...
12 },
13 {
14 ON: 'HASH',
15 PREFIX: 'messages'
16 });
17 } catch (e) {
18 if (e.message === 'Index already exists') {
19 console.log('Index exists already, skipped creation.');
20 } else {
21 // Something went wrong, perhaps RediSearch isn't installed...
22 console.error(e);
23 process.exit(1);
24 }
25 }
26 }
22 ChatController.execTransactionMessagesUpdate(shouldRedisUpdate, importMul
23
24 return filteredMessages;
25 }
Строка 1.
https://habr.com/ru/article/edit/800379/ 9/14
whereCriteria — Мы уже видели этот универсальный объект с
10.04.2024, 22:15 Редактирование статьи / Хабр
https://habr.com/ru/article/edit/800379/ 11/14
Далее просто выполняем транзакцию, где записи обновляются
10.04.2024, 22:15 Редактирование статьи / Хабр
массово.
1 static execTransactionMessagesUpdate = (redisUpdate, importMulti) => {
2 if (redisUpdate) {
3 importMulti.exec(function(err,results){
4 if (err) { throw err; } else {
5 console.log(results);
6 client.quit();
7 }
8 });
9 }
10 }
Заключение.
Это основное, что я хотел показать; возможно, внимательный
читатель заметит, что есть еще и другие модули, вроде RedisJson, но
почему я не использовал его для подобной задачи, написал выше.
Еще в RediSearch полно и других команд вроде FT.AGGREGATE...
Цель же статьи — показать, насколько мощны модули, особенно
RediSearch, и то, что можно получить видимые профиты, используя их.
Например, существенно сэкономить машинные ресурсы, используя
правильный подход. Что было и сделано в конкретной бизнес-задаче.
Экономия ресурсов была существенной, но еще более
существенной была экономия нервных клеток заказчика
по сравнению с традиционным способом получения данных из Redis
(без использования модулей).
Сам же официальный список модулей с их кратким описанием можно
взять на официальном сайте Redis — здесь.
Нажмите "/" для вызова меню
Далее к настройкам
ХАБР ИЩЕТ АВТОРОВ
https://habr.com/ru/article/edit/800379/ 12/14
10.04.2024, 22:15 Редактирование статьи / Хабр
НОВЫЙ РЕДАКТОР
ПАМЯТКА АВТОРУ
Настройка языка
Техническая поддержка
© 2006–2024, Habr
https://habr.com/ru/article/edit/800379/ 14/14