Кэширование в JavaScript: Redis, Memcached и встроенные решения

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Кэширование в JavaScript: Redis, Memcached и встроенные решения: от А до Я

В современной веб-разработке на Node.js производительность приложения напрямую зависит от скорости доступа к данным. Каждый запрос к базе данных, внешнему API или файловой системе создаёт задержку, которая накапливается при росте нагрузки. Кэширование — это стратегия временного хранения часто запрашиваемых данных в быстром хранилище, позволяющая сократить время ответа в 10–100 раз. В этой статье мы разберём три подхода к кэшированию в JavaScript: встроенные решения (Map, WeakMap, модуль node-cache), распределённые системы Redis и Memcached, а также их комбинации.

Зачем нужно кэширование в Node.js?

Основная цель кэширования — снизить нагрузку на медленные ресурсы (базы данных, диски, внешние сервисы) и ускорить отдачу данных пользователю. В типичном веб-приложении на Node.js кэш может хранить:

  • Результаты сложных запросов к БД (агрегации, JOIN).
  • Ответы от внешних API (погода, курсы валют, геоданные).
  • Сессии пользователей и токены аутентификации.
  • HTML-фрагменты или целые страницы (SSR кэширование).
  • Конфигурационные файлы и шаблоны.

Без кэширования каждое повторное обращение к одним и тем же данным приводит к дублированию работы. С кэшем — данные извлекаются из оперативной памяти за микросекунды.

Встроенные решения для кэширования в JavaScript

Для простых сценариев или однопоточных приложений можно использовать нативные структуры данных JavaScript. Они не требуют установки внешних пакетов, но имеют ограничения по объёму и времени жизни.

1. Map и WeakMap

Объект Map — это коллекция ключ-значение, идеально подходящая для кэша в рамках одного процесса. Пример простого кэша с TTL (time-to-live):

class SimpleCache {
  constructor(ttl = 60000) {
    this.cache = new Map();
    this.ttl = ttl;
  }

  set(key, value) {
    this.cache.set(key, {
      value,
      expiry: Date.now() + this.ttl
    });
  }

  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }
    return item.value;
  }

  has(key) {
    return this.get(key) !== null;
  }
}

// Использование
const cache = new SimpleCache(5000); // TTL 5 секунд
cache.set('user:123', { name: 'Иван' });
console.log(cache.get('user:123')); // { name: 'Иван' }

WeakMap отличается тем, что его ключи — только объекты, и сборщик мусора может удалять записи, если на объект-ключ больше нет ссылок. Это удобно для кэширования DOM-элементов или временных объектов.

2. Модуль node-cache

Для production-среды лучше использовать готовую библиотеку node-cache. Она поддерживает TTL, автоматическую очистку и работает быстрее самописного решения:

const NodeCache = require('node-cache');
const myCache = new NodeCache({ stdTTL: 100, checkperiod: 120 });

// Запись
myCache.set('key', { data: 'value' });

// Чтение
const value = myCache.get('key');
if (value === undefined) {
  // Кэш промах — нужно получить данные из БД
}

// Удаление
myCache.del('key');

Встроенные решения подходят для монолитных приложений или микросервисов с одним экземпляром. Однако при масштабировании на несколько процессов или серверов данные становятся несогласованными — здесь нужны распределённые кэши.

Redis: мощный in-memory data store

Redis — это высокопроизводительное хранилище данных в оперативной памяти, поддерживающее строки, хэши, списки, множества и другие структуры. Для Node.js используется пакет redis или ioredis. Redis идеален для кэширования благодаря:

  • Поддержке TTL на уровне ключа (команда EXPIRE).
  • Атомарным операциям (INCR, DECR, SETNX).
  • Встроенной репликации и кластеризации.
  • Возможности сохранять данные на диск (RDB/AOF).

Пример кэширования с Redis в Node.js

const Redis = require('ioredis');
const redis = new Redis({
  host: 'localhost',
  port: 6379,
  retryStrategy: (times) => Math.min(times * 50, 2000)
});

async function getCachedData(key) {
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // Имитация получения данных из БД
  const freshData = { id: 1, name: 'Тестовые данные' };
  
  // Сохраняем в кэш на 60 секунд
  await redis.setex(key, 60, JSON.stringify(freshData));
  return freshData;
}

// Использование
getCachedData('product:42').then(data => console.log(data));

Redis также поддерживает паттерн "кэш-ассид" (cache-aside): приложение сначала проверяет кэш, при промахе загружает данные из БД и сохраняет их в Redis. Это наиболее распространённая стратегия.

Продвинутые возможности Redis

С помощью Redis можно реализовать rate limiting, очереди задач (через списки), сессионные хранилища и даже полнотекстовый поиск (через модуль RediSearch). Для кэширования особенно полезны:

  • INCR — счётчики посещений.
  • ZADD / ZRANGE — кэширование топ-рейтингов.
  • PUBLISH / SUBSCRIBE — инвалидация кэша в реальном времени.

Memcached: лёгкий и быстрый

Memcached — это распределённая система кэширования, ориентированная исключительно на хранение пар ключ-значение. В отличие от Redis, Memcached не поддерживает постоянное хранение (всё хранится только в RAM) и имеет более простую модель данных. Для Node.js используется пакет memcached.

Установка и пример

Блоги

Рекомендаций по книгам