Mise en cache en TypeScript : Redis, Memcached et solutions intégrées (niveau avancé)

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi la mise en cache avancée est une nécessité pour les applications TypeScript

\n\n

Dans les systèmes modernes à forte charge, la mise en cache a cessé d'être une option — c'est un élément architectural obligatoire. Pour les développeurs TypeScript travaillant avec Node.js, le choix d'une stratégie de mise en cache appropriée peut réduire le temps de réponse de l'API de 200 ms à 2 ms et diminuer la charge sur la base de données de 80 à 90 %. Dans cet article, nous examinerons trois approches de mise en cache à un niveau avancé : Redis, Memcached et les solutions intégrées en TypeScript.

\n\n

1. Mise en cache intégrée en TypeScript : du simple Map au cache LRU

\n\n

Les solutions intégrées sont idéales pour les applications monolithiques ou les microservices où un cache distribué n'est pas nécessaire. L'option la plus primitive est l'utilisation de Map, mais elle ne convient pas à la production en raison de l'absence de TTL et de contrôle de la mémoire.

\n\n

Implémentation d'un cache LRU avec TTL

\n\n

Considérons une implémentation avancée d'un cache LRU (Least Recently Used) avec nettoyage automatique :

\n\n
interface CacheEntry<T> {\n  value: T;\n  expiresAt: number;\n}\n\nclass LRUCache<T> {\n  private cache: Map<string, CacheEntry<T>>;\n  private readonly maxSize: number;\n  private readonly ttlMs: number;\n\n  constructor(maxSize: number = 100, ttlMs: number = 60000) {\n    this.cache = new Map();\n    this.maxSize = maxSize;\n    this.ttlMs = ttlMs;\n  }\n\n  get(key: string): T | undefined {\n    const entry = this.cache.get(key);\n    if (!entry) return undefined;\n\n    if (Date.now() > entry.expiresAt) {\n      this.cache.delete(key);\n      return undefined;\n    }\n\n    // Déplace la clé à la fin (la plus récente)\n    this.cache.delete(key);\n    this.cache.set(key, entry);\n    return entry.value;\n  }\n\n  set(key: string, value: T): void {\n    if (this.cache.has(key)) {\n      this.cache.delete(key);\n    } else if (this.cache.size >= this.maxSize) {\n      // Supprime l'élément le plus ancien (le premier)\n      const oldestKey = this.cache.keys().next().value;\n      this.cache.delete(oldestKey);\n    }\n\n    this.cache.set(key, {\n      value,\n      expiresAt: Date.now() + this.ttlMs,\n    });\n  }\n\n  clear(): void {\n    this.cache.clear();\n  }\n}\n\n// Utilisation\nconst userCache = new LRUCache<User>(500, 300000); // 500 éléments, TTL de 5 minutes
\n\n

Pattern avancé : décorateur de mise en cache

\n\n

Pour la propreté du code, utilisons les décorateurs TypeScript :

\n\n
function Cached(ttlMs: number = 60000) {\n  const cache = new LRUCache<any>(100, ttlMs);\n\n  return function (\n    target: any,\n    propertyKey: string,\n    descriptor: PropertyDescriptor\n  ) {\n    const originalMethod = descriptor.value;\n\n    descriptor.value = async function (...args: any[]) {\n      const key = `${propertyKey}_${JSON.stringify(args)}`;\n      const cached = cache.get(key);\n      if (cached !== undefined) return cached;\n\n      const result = await originalMethod.apply(this, args);\n      cache.set(key, result);\n      return result;\n    };\n\n    return descriptor;\n  };\n}\n\nclass UserService {\n  @Cached(120000) // 2 minutes\n  async getUser(id: string): Promise<User> {\n    // Requête coûteuse à la base de données\n    return db.findUser(id);\n  }\n}
\n\n

2. Redis : mise en cache distribuée avec des structures de données avancées

\n\n

Redis n'est pas simplement un stockage key-value. Sa prise en charge de structures de données complexes (Hash, List, Set, Sorted Set) ouvre des possibilités pour implémenter des stratégies de mise en cache avancées.

\n\n

Mise en cache avec invalidation par tags

\n\n

Problème : lors de la mise à jour d'une entité, il faut invalider plusieurs caches. Solution — les tags :

\n\n
import Redis from 'ioredis';\n\nclass TaggedCache {\n  private redis: Redis;\n  private readonly keyPrefix: string;\n\n  constructor(redisUrl: string, prefix: string = 'cache') {\n    this.redis = new Redis(redisUrl);\n    this.keyPrefix = prefix;\n  }\n\n  async get<T>(key: string,                

Blogs

Book Recommendations