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

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

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

Начать курс

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

Современные веб-приложения на TypeScript требуют высокой скорости отклика и эффективного управления ресурсами. Одним из ключевых инструментов для достижения этой цели является кэширование. В этой статье мы подробно разберем три основных подхода к кэшированию в экосистеме TypeScript/Node.js: использование Redis, Memcached и встроенных решений (in-memory cache). Вы узнаете, как выбрать подходящий инструмент для вашей задачи и увидите рабочие примеры кода.

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

Кэширование позволяет временно хранить часто запрашиваемые данные в быстром хранилище, чтобы сократить время ответа и снизить нагрузку на базы данных или внешние API. В TypeScript, работающем на Node.js, кэширование особенно полезно для:

  • Ускорения повторяющихся запросов к базе данных;
  • Снижения задержек при обращении к внешним сервисам;
  • Оптимизации вычислительно сложных операций;
  • Управления сессиями пользователей.

Рассмотрим три основных типа кэширования, доступных разработчику на TypeScript.

1. Встроенное кэширование (In-Memory Cache)

Самый простой и быстрый способ — хранить данные в памяти самого процесса Node.js. Для этого можно использовать Map или более продвинутые библиотеки, такие как node-cache.

Преимущества:

  • Максимальная скорость (отсутствие сетевых вызовов);
  • Простота реализации;
  • Не требует установки внешних сервисов.

Недостатки:

  • Данные теряются при перезапуске приложения;
  • Ограничено объемом оперативной памяти одного процесса;
  • Не работает в кластерном режиме (каждый процесс имеет свой кэш).

Пример с использованием node-cache

Установите библиотеку:

npm install node-cache

Реализация простого сервиса кэширования:

import NodeCache from 'node-cache';

class MemoryCacheService {
  private cache: NodeCache;

  constructor(ttlSeconds: number = 600) {
    this.cache = new NodeCache({ stdTTL: ttlSeconds, checkperiod: 120 });
  }

  public get<T>(key: string): T | undefined {
    return this.cache.get<T>(key);
  }

  public set<T>(key: string, value: T, ttl?: number): boolean {
    return this.cache.set(key, value, ttl);
  }

  public has(key: string): boolean {
    return this.cache.has(key);
  }

  public del(key: string): number {
    return this.cache.del(key);
  }

  public flush(): void {
    this.cache.flushAll();
  }
}

// Использование
const cacheService = new MemoryCacheService(300); // TTL = 5 минут

async function getData(id: string): Promise<any> {
  const cached = cacheService.get<any>(`data:${id}`);
  if (cached) {
    return cached;
  }

  // Имитация дорогой операции
  const data = await fetchFromDatabase(id);
  cacheService.set(`data:${id}`, data);
  return data;
}

2. Кэширование с Redis

Redis — это мощное in-memory хранилище данных, которое часто используется как кэш. Он поддерживает сложные структуры данных (строки, хеши, списки, множества) и может работать в кластерном режиме.

Преимущества:

  • Персистентность (опционально);
  • Поддержка сложных структур данных (например, сортированные множества);
  • Встроенные механизмы TTL (Time-To-Live);
  • Отличная производительность (до 100 000 операций/сек);
  • Поддержка Pub/Sub для обмена сообщениями.

Недостатки:

  • Требует установки и настройки отдельного сервера;
  • Использует больше памяти, чем встроенные решения;
  • Сетевые задержки (хотя и минимальные).

Пример работы с Redis в TypeScript

Установка:

npm install redis

Типизированный сервис для работы с Redis:

import { createClient, RedisClientType } from 'redis';

interface CacheConfig {
  url?: string;
  ttl?: number;
}

class RedisCacheService {
  private client: RedisClientType;
  private defaultTTL: number;

  constructor(config: CacheConfig = {}) {
    this.client = createClient({ url: config.url || 'redis://localhost:6379' });
    this.defaultTTL = config.ttl || 3600; // 1 час по умолчанию

    this.client.on('error', (err) => console.error('Redis Client Error', err));
    this.client.connect();
  }

  public async get<T>(key: string): Promise<T | null> {
    const value = await this.client.get(key);
    if (value) {
      return JSON.parse(value) as T;
    }
    return null;
  }

  public async set<T>(key: string, value: T, ttl?: number): Promise<void> {
    const stringValue = JSON.stringify(value);
    const expireTime = ttl || this.defaultTTL;
    await this.client.setEx(key, expireTime, stringValue);
  }

  public async del(key: string): Promise<void> {
    await this.client.del(key);
  }

  public async flush(): Promise<void> {
    await this.client.flushAll();
  }

  public async disconnect(): Promise<void> {
    await this.client.quit();
  }
}

// Использование
const redisCache = new RedisCacheService({ ttl: 600 }); // TTL = 10 минут

async function getUserProfile(userId: string): Promise<UserProfile> {
  const cacheKey = `user:profile:${userId}`;
  const cached = await redisCache.get<UserProfile>(cacheKey);
  
  if (cached) {
    return cached;
  }

  const profile = await database.findUserProfile(userId);
  await redisCache.set(cacheKey, profile, 300); // переопределяем TTL
  return profile;
}

3. Кэширование с Memcached

Memcached — это распределенная система кэширования памяти, оптимизированная для хранения небольших объемов данных (обычно до 1 МБ на ключ).

Преимущества: