Галоўная / Артыкулы / Redis за межамі кэшавання: сесіі, ліміты частоты, чергі та модель Pub/Sub у Node.js

Redis за межамі кэшавання: сесіі, ліміты частоты, чергі та модель Pub/Sub у Node.js

Семь шаблонава Redis для сервераў на Node.js — кэшаванне з таймамі жыцця, клучы OTP, ліміты частоты запытоў, заданні BullMQ, сесіі, ліміты моделі Pub/Sub, а таксама калі не трэба вжываць Redis.

1424 слоў

Пачатковыя ментальныя моделі спрыяюць розумеўцу Redis як «толькі кэша»: зберагчы значэнне, задаючы тэрмін його дзейнасці, чытаючы яго быстрэй, чым базу дадзеных, і готава.

Гэтыя уявленні не ўсунутыя. Яны непашчэрпні.

На практыцы Redis викорыстоўваецца для швайнах адпаведзей API, спяльных сэсій, лічылакаў зловжывання, одноразовых кодаў, очаквальных черг заданняў, лёгкаг розповсюджэння інформацыі у реальны час і іншых трымкучых значэнняў.

Кращая канцепцыя: спрыяюць Redis як швайны хранальнік дадзеных у памяці з многама задачамі на бэкендзе — кэшаванне ўсьмо толькі першая з іх.

1. Redis можа значна прышвартаваць API

Пачніце з кэшавання.

Разглянем GET /products.

Без кэша кожны запит можа выглядаць так:

Кліент → API на Node.js → PostgreSQL → API на Node.js → Кліент

Дорогі запыт пад тыясячамі запускаў значыць, што база дадзеных павтарае тую ж самую роботу.

Redis можа стаць між такім запытом.

Кліент → API Node.js → Redis

Пры ўспаможнай запыткі — негайна адпаведзь. Пры неуспешнай запыткі — выкарыстаць PostgreSQL, зберагчы рэзультат у Redis, а пасля — адпаведзець.

Просты прыклад на ioredis:

import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);
async function getProducts() {
  const cached = await redis.get("products");
  if (cached) {
    return JSON.parse(cached);
  }
  const products = await database.product.findMany();
  await redis.set(
    "products",
    JSON.stringify(products),
    "EX",
    300
  );
  return products;
}h

Тут EX означае, што кэшаваны данні выгораюць чырае 300 секунд.

Існуе ўжо адна серьёзная проблема: анавярэнне кэшу.

Падазроўваючы, што у Redis зберагнута інформацыя product:123 → price:500, а ў PostgreSQL — 600, база дадзенаў правильная; пры тым Redis можа аддаць 500.

Кэшаванне — гэта не проста «зберагчы всё у Redis». Командам усё рава трэба разважаць пра:

  • TTL
  • Анавярэнне кэшу
  • Старыя данні
  • Неуспешныя запыткі
  • Працоўнія нештасці кэшу

Зберагчы значэнне ў Redis лёгка. Але падтрымваць яго правільнаю інформацыяю — сложней.

2. Redis чырэ падходзіць для тымчасовых дадзенаў

Значэнні з короткім трыманням ўсунуцца ідеальна: коды для адхоўвання ўваходу на адну раз, лінкі для перазначэння пароля, токены паўеры, тымчасовыя блобы сесій, лічылкі зловжыванняў і блакіранні для захавы.

Прыклад: выдача коду на адну раз:

const otp = "482913";
await redis.set(
  `otp:${userId}`,
  otp,
  "EX",
  300
);

Код OTP автаматычна выгорае пасля пяці хвілін.

Не трэба спецыяльной табелі для OTP. Таксама не трэба окольнаго задання для чысткі.

Чытайце яго знову за дапамою:

const otp = await redis.get(`otp:${userId}`);

Пасля заканчэння TTL Redis адмахвае ключ за правіламі яго выгорання.

Такі падход робіць Redis ідеальным месца для данных прыкладнага програмісты з короткім трыманням.

3. Redis можа дапамагчы ў обмежэнні частоты запытанняў

Возьмімо POST /login.

Без обмежэнняў кліент можа запускаць масовыя спробы адхоўвання ўваходу — тыячы запытанняў паспалоха.

Redis можа хаваць лічылак для кліента:

const key = `login-attempts:${ip}`;
const attempts = await redis.incr(key);
if (attempts === 1) {
  await redis.expire(key, 60);
}
if (attempts > 10) {
  throw new Error("Too many requests");
}

Структура такая: IP → лічылак у Redis → колькасць → ліміт.

Гэта мае большое значэнне, калі за лоад-балансерам знаходзяцца калькольванніка API. Калькольваннікі ў памяці на адзін процэс не являюцца глобальнымі. Redis з’яўляецца як спакоючы сховішча для гэтых сервераў.

4. Redis можа выконваць фонавыя заданні

Пры стварэнні адначкі можа знадобіцца стварыць пользователя, апраўліць пісьмо з прыемам, сгенераваць данні, паведаміць іншую службу та выконаць іншыя задачы.

Запит HTTP не должен чакаць на выконанне всіх гэтых дзеянняў.

Замест таго перадаюце задачу ў очакальную лісту:

Кліент → API → Ліста → Адпаведзь

Потым:

Ліста → Рабочы процэс → Выконанне задання

BullMQ — это популярны варыянт для Node.js, які выкарыстоўвае Redis:

await emailQueue.add("welcome-email", {
  userId: user.id,
  email: user.email,
});

Рабочы процэс выконвае заданне окрема:

const worker = new Worker(
  "email",
  async (job) => {
    if (job.name === "welcome-email") {
      await sendWelcomeEmail(job.data.email);
    }
  },
  {
    connection: redisConnection,
  }
);

API не трэба чакаць на адпаведзь від прадаўця электранайпісоў, пры тым як адпавядае корыстніку.

Гэта падходзіць для заданняў, якія выконваюцца медленна, можна прабаваць знову, залежныя ад зовнішнях служб, вимагаюцы большай канцэнтраціі CPU, або якія не ўсё ж такі не патрэбны пры адпаведзі API.

Раздзеленыя абавязкі: API обрабоцвае запыт; працоўнік адпавядае за складную работу.

5. Redis можа зберагаць сесіі

Кантроль сесій таксама ўзможлівае выкарыстоўванне Redis. Ключ на кшталт session:abc123 можа хаваць:

{
  "userId": "123",
  "role": "ADMIN"
}

Гэта становіць ценнасць, калі калькі задніх сервераў дзеляцца адной базай сесій через Redis.

Важлівае адразненне: Redis не робіць автаматычна аутентыкацыю безпечной.

Командам усё рава трэба кантролюваць ідэнтыфікаторы сесій, захіщаныя кукі, тэрмін дзейнасці, CSRF, калі гэта прыемліва, а таксама аутентыкацыю і автарызацыю.

Redis — это інфраструктура, а не стратэгія безпекі.

6. Redis можа дапамагчы ў функцыях у рэальны час

Механізм Pub/Sub дазволяе распрастраняць запускі між інстанцамі. Адна з схем выглядае так: кліент атакуе сервер А, пракладае данні ў Redis, на серверы B працюе обробнік падпіску, а потым данні дастаюцца іншаму кліенту.

Ілюстрацыя:

await redis.publish(
  "notifications",
  JSON.stringify({
    userId: "123",
    message: "Your order has shipped",
  })
);
await subscriber.subscribe("notifications")
subscriber.on("message", (channel, message) => {
  console.log(channel, message);
});

Падходзіць для паведамленняў, жывых апошніх змян, процэсаў, relacionаваных з чатамі, і распространення аўтаматаў.

Абмежэнне: Redis Pub/Sub не ўтварае надзеянай чергі паведамленняў.

Якщо важліва надзеяна обработка, пракаты або гарантавана доставка, залежна ад ситуацыі кращэ выбраць чергу або Redis Streams.

Важна разумець гэтыя адрозненні.

7. Redis стае проблемай, якщо яго викорыстоўваюць усюды

Найважлівейшы урок: калі ёсць можласць викорыстоўваць Redis, бывае спакуса пасунуць туды все.

Не робіце гэтага.

Толькі швальнасць не значыць, што кожны дадзенык павінен знаходзіцца ў памяці.

PostgreSQL можа застацца стаўкам правды для бізнес-дадзенняў, тады як Redis абавяжаецца кэшам, сесіямі, OTP-кодамі, лімітамі частоты і чергамі.

Практычны ўдзеленне дапамагае зберагаць надзейныя бізнес-даныя ў PostgreSQL, а Redis выкорыстоўваецца для актыўных трафікаў, короткага часу жыцця даных і падтрымкі такіх заведамасцей, як чергі чыста лічыльнікі.

Якщо з самага пачатку чытка адзначыць граніцы, можна заўсёды ухиліцца ад многіх пазнейшых переработак.

Структуры даных Redis маюць значэнне

Redis — гэта не толькі ключ → строка. Ён адказвае за кілька разных структураў.

Строкі

Простыя значэння, напрыклад user:123:name → „Mit“.

Хешы

Калькі поль пад адним ключам:

user:123
name → Mit
role → ADMIN
email → example@email.com

Спісы

Упорядкованыя колекцыі і дзеяння, сэродзеленыя з чергамі.

Множыны

Унікальныя значэння.

Упорядкованыя множыны

Элементы, упорядкованыя па рэйтынгу — напрыклад, табліця лідэраў:

1000 → Player A
900  → Player B
800  → Player C

Выбір правильнай структуры часта спраблевае проблему.

Пашчотныя памылкі ў викорыстоўванні Redis, якіх трэба ухыляцца

Памылка 1: кэшаванне всьога

Не кожны запит трэбуе кэша. Кэшаванне прыносіць дапэўню складнасцяў. Якщо запіт вже дастатньа шырока, Redis можа рашыць проблему, якой няма.

Памылка 2: абсэнцыя терміну выканання

Вялікія колькасці временных дадзэнняў без термінаў выканання накапліваюцца. Якщо дадзеныя не патрабуецца зберагаць вечна, задайце ўсё-такі політыку терміну выканання.

Памылка 3: спрыяванне Redis як стацыонарнай базе дадзэнняў

Якщо Redis зберагае ўсю едынственную копію важлівых бізнес-дадзэнняў, система становіцца вельмі залежной ад яго. Павінны быць вядомы істочнік правдывых дадзэнняў.

Памылка 4: ігнараванне нештачакоў у Redis

Адначасова падберыце, што будзе дэйстваць, калі Redis не працуе. Для багато сцэнарыяў викорыстання кэша дапускаецца перайшча на базу дадзэнняў. Правыя стратэгіі залежаць ад ролі, яку выплявае Redis.

Памылка 5: викорыстанне Redis без разумення навантажэння

Скорасць не ўзлімітаваная. Яшчэ трэба разважыць пра памяці, выгнанні дадзеных, з’ўязках, дыяграмах ключоў, TTL-ах, серіяванні, затрымкі ў сецыі і патрэбах утрымання дадзеных.

Як Redis зменяе падход да бэкенду

Багатыя проекты пачынаюцца з обробніка запитоў, які працуе безпосередна з SQL.

Калі з’являюцца памятны сховыш і задачі, якія выкананы пазней, шлях часта стае сложнейшым: обробнік спачатку пераглядае Redis, а потым базу дадзеных; або ж він паказвае задачу на обработку працавальніку, які взаўсёды працуе з зовнішнім прадавцам.

Бэкенды стаюць сукупнасцям спецыялізаваных элементаў. Redis — адны з такіх элементаў, які можа выступаць у болей чым адной ролі.

Заключныя заўважэння

Не адмахваюцеся ад Redis таму, што ўсі іншы яго вжываюць.

З’явілася можлівасць — адаптуйцеся: кэшаванне для частых запыткаў, ключы TTL для трымкі секрэтаў на корткі час, лямштыкі для контролю за зловжываннямі, абераткі для запыткаў, якія трэба выконаць пазней, спакульная база дадзеных для сэсій між экземплярамі, або модель Pub/Sub, калі дастатнек павольнаг распрасцэрання інформацыі.

Утримайцеся ад таго, каб Redis стаў стандартным рашэнням для кожнага пытання, якое выступае ў ролі бэкенду.

Хорашыя системы — это не тые, у якіх самыя дужэ большыя спісы інструментаў. Це тые, у якіх кожны інструмент заслуговае на свое месца.