Кэширование в JavaScript: Redis, Memcached и встроенные решения
Кэширование — одна из ключевых стратегий оптимизации производительности веб-приложений. В экосистеме JavaScript (особенно в Node.js) разработчики имеют доступ к мощным инструментам: от встроенных механизмов до распределённых систем вроде Redis и Memcached. В этой статье мы разберём, как и когда использовать каждый из подходов, с реальными примерами кода.
Зачем нужно кэширование в Node.js?
Без кэширования каждый запрос к серверу может приводить к дорогостоящим операциям: чтению из базы данных, сложным вычислениям или вызовам внешних API. Кэш сохраняет результат первого запроса и отдаёт его при повторных обращениях. Это снижает нагрузку на сервер, уменьшает время ответа и улучшает пользовательский опыт.
Основные сценарии использования кэша в Node.js:
- Результаты запросов к базе данных (особенно агрегаций)
- Ответы внешних API (погода, курсы валют)
- Тяжёлые вычисления (генерация отчётов, обработка изображений)
- Сессии пользователей и токены аутентификации
Встроенное кэширование в JavaScript (Node.js)
Простейший способ — использовать объект Map или Object для хранения данных в памяти процесса. Это быстро, но имеет ограничения: данные живут только пока работает сервер, и память не ограничена.
Пример: Кэш на Map с TTL (Time To Live)
class SimpleCache {
constructor(ttl = 60000) {
this.cache = new Map();
this.ttl = ttl; // время жизни в мс (по умолчанию 1 минута)
}
set(key, value) {
this.cache.set(key, {
value,
timestamp: Date.now()
});
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
delete(key) {
this.cache.delete(key);
}
clear() {
this.cache.clear();
}
}
// Использование
const cache = new SimpleCache(30000); // 30 секунд
cache.set('user_123', { name: 'Иван', role: 'admin' });
const user = cache.get('user_123');
console.log(user); // { name: 'Иван', role: 'admin' }
Плюсы: нулевая задержка, простота, не требует внешних зависимостей.
Минусы: данные теряются при перезапуске, ограничены памятью одного процесса, не подходит для распределённых систем.
Для более продвинутого встроенного кэша можно использовать пакет node-cache, который добавляет автоматическую очистку, статистику и поддержку строковых ключей.
Redis: распределённый кэш для Node.js
Redis — это in-memory хранилище данных, которое часто используется как кэш. В Node.js для работы с Redis используется пакет ioredis (более современный, чем redis).
Установка и базовое подключение
npm install ioredis
const Redis = require('ioredis');
const redis = new Redis({
host: 'localhost',
port: 6379,
// password: 'your-password' // если требуется
});
redis.on('connect', () => console.log('Подключено к Redis'));
redis.on('error', (err) => console.error('Redis ошибка:', err));
Пример: Кэширование данных с TTL
const Redis = require('ioredis');
const redis = new Redis();
async function getCachedData(key, fetchFunction, ttl = 3600) {
// Пытаемся получить из кэша
const cached = await redis.get(key);
if (cached) {
return JSON.parse(cached);
}
// Если нет — получаем данные и сохраняем
const data = await fetchFunction();
await redis.setex(key, ttl, JSON.stringify(data));
return data;
}
// Пример использования: кэширование ответа API
async function fetchWeather(city) {
const response = await fetch(`https://api.weather.com/${city}`);
return response.json();
}
// Кэшируем на 5 минут (300 секунд)
const weather = await getCachedData('weather:moscow', () => fetchWeather('moscow'), 300);
console.log(weather);
Продвинутые возможности Redis
- Структуры данных: хэши, списки, множества, сортированные множества
- Pub/Sub: для уведомлений об инвалидации кэша
- Lua-скрипты: атомарные операции с кэшем
- Кластеризация: для горизонтального масштабирования
Плюсы: распределённый, быстрый, поддерживает сложные структуры, сохраняет данные при перезапуске (RDB/AOF).
Минусы: требует отдельного сервера, потребляет много оперативной памяти, сложнее в настройке.
Memcached: лёгкий и быстрый
Memcached — это специализированная система кэширования, проще Redis, но с меньшим функционалом. Для Node.js используется пакет memcached.
Установка и подключение
npm install memcached
const Memcached = require('memcached');
const memcached = new Memcached('localhost:11211');
memcached.on('issue', (details) => {
console.error('Memcached проблема:', details);
});
Пример: Кэширование с Memcached
const Memcached = require('memcached');
const memcached = new Memcached('localhost:11211');
function cacheData(key, data, ttl = 3600) {
return new Promise((resolve, reject) => {
memcached.set(key, data, ttl, (err) => {
if (err) reject(err);
else resolve();
});
});
}
function getCached(key) {
return new Promise((resolve, reject) => {
memcached.get(key, (err, data) => {
if (err) reject(err);
else resolve(data || null);
});
});
}
// Использование
async function example() {
await cacheData('session:user42', { id: 42, name: 'Анна' }, 1800);
const session = await getCached('session:user42');
console.log(session); // { id: 42, name: 'Анна' }
}