🔴 BD07 — Redis Fondamentaux
1. Introduction à Redis
Redis (Remote Dictionary Server) est un store de données en mémoire, ultra-rapide (< 1 ms), utilisé comme cache, broker de messages, gestionnaire de sessions et bien plus.
Cas d'usage
| Cas d'usage | Structure Redis |
|---|---|
| Cache de requêtes API | String (JSON sérialisé) |
| Sessions utilisateur | Hash |
| File de tâches | List (LPUSH/BRPOP) |
| Tags & sets d'utilisateurs | Set |
| Leaderboards / classements | Sorted Set |
| Compteurs, rate limiting | String (INCR) |
| Pub/Sub messagerie | Channel |
| Streams temps réel | Stream (XADD) |
npm install ioredis
# ou
npm install redis
const Redis = require('ioredis');
const redis = new Redis({
host: process.env.REDIS_HOST || '127.0.0.1',
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
db: 0,
retryStrategy: (times) => Math.min(times * 50, 2000)
});
2. Strings
Type de base : texte, entiers, binaires. Max 512 Mo.
// SET / GET
await redis.set('user:42:name', 'Alice');
const name = await redis.get('user:42:name');
// SET avec expiration
await redis.set('session:abc', JSON.stringify({ userId: 42 }), 'EX', 3600); // 1h
await redis.setex('token:xyz', 900, 'data'); // 15 min
// Compteurs atomiques
await redis.incr('page:home:views');
await redis.incrby('stats:logins', 1);
await redis.decr('stock:product:1');
// Opérations multiples
await redis.mset('key1', 'val1', 'key2', 'val2');
const vals = await redis.mget('key1', 'key2');
// NX = only if Not eXists
const ok = await redis.set('lock:resource', '1', 'EX', 30, 'NX');
// ok = 'OK' si obtenu, null sinon
3. Lists
Liste doublement chaînée. Idéal pour files de messages, historiques récents.
// LPUSH / RPUSH
await redis.lpush('queue:emails', JSON.stringify({ to: 'alice@test.com', subject: 'Bienvenue' }));
await redis.rpush('history:user:42', 'product:1', 'product:5');
// Pop bloquant (file de workers)
const [list, item] = await redis.blpop('queue:emails', 5); // timeout 5s
if (item) {
const task = JSON.parse(item);
await sendEmail(task);
}
// Consultation
const recent = await redis.lrange('history:user:42', 0, 9); // 10 derniers
const length = await redis.llen('queue:emails');
// Garder seulement les N derniers
await redis.ltrim('history:user:42', 0, 49); // garder 50 max
4. Sets
Ensemble non ordonné de membres uniques. Opérations d'ensemble très efficaces.
// Ajouter / retirer
await redis.sadd('tags:post:1', 'javascript', 'redis', 'backend');
await redis.srem('tags:post:1', 'redis');
// Vérifier l'appartenance
const isMember = await redis.sismember('online:users', '42'); // 0 ou 1
// Lister
const members = await redis.smembers('tags:post:1');
const count = await redis.scard('online:users');
// Opérations d'ensemble
const common = await redis.sinter('friends:alice', 'friends:bob'); // intersection
const all = await redis.sunion('online:FR', 'online:BE'); // union
const diff = await redis.sdiff('subscribers:plan:pro', 'paid'); // différence
// Déplacer un membre
await redis.smove('online:users', 'away:users', '42');
5. Hashes
Dictionnaire clé-valeur. Parfait pour stocker les attributs d'un objet.
// HSET / HGET
await redis.hset('user:42', {
name: 'Alice Dupont',
email: 'alice@example.com',
role: 'admin',
loginCount: '0'
});
const email = await redis.hget('user:42', 'email');
const user = await redis.hgetall('user:42'); // objet complet
// Incrémenter un champ
await redis.hincrby('user:42', 'loginCount', 1);
// Vérifier / supprimer un champ
const exists = await redis.hexists('user:42', 'phone');
await redis.hdel('user:42', 'tempToken');
// Lister les champs
const keys = await redis.hkeys('user:42');
const values = await redis.hvals('user:42');
const len = await redis.hlen('user:42');
6. Sorted Sets (ZSets)
Ensemble avec score flottant. Membres triés par score. Idéal pour leaderboards.
// ZADD
await redis.zadd('leaderboard:game', 1500, 'alice', 2300, 'bob', 900, 'charlie');
// Classement (du plus grand score)
const top10 = await redis.zrevrange('leaderboard:game', 0, 9, 'WITHSCORES');
// Rang d'un joueur (0-based)
const rank = await redis.zrevrank('leaderboard:game', 'alice');
const score = await redis.zscore('leaderboard:game', 'alice');
// Incrémenter le score
await redis.zincrby('leaderboard:game', 50, 'alice');
// Plage de scores
const midRange = await redis.zrangebyscore('leaderboard:game', 1000, 2000);
// Supprimer
await redis.zrem('leaderboard:game', 'charlie');
const count = await redis.zcard('leaderboard:game');
7. TTL & Expiration
// Définir un TTL
await redis.expire('cache:users', 300); // 5 min (secondes)
await redis.pexpire('rate:ip:1.2.3.4', 60000); // 60s (ms)
// Vérifier le TTL restant
const ttl = await redis.ttl('session:abc'); // secondes (-2 = n'existe pas)
const pttl = await redis.pttl('session:abc'); // millisecondes
// Supprimer le TTL (rendre persistant)
await redis.persist('important:key');
// Supprimer une clé
await redis.del('temp:data');
await redis.del('key1', 'key2', 'key3'); // multiple
// Vérifier l'existence
const exists = await redis.exists('user:42'); // 1 ou 0
// Pattern scan (préférer SCAN à KEYS en prod)
const [cursor, keys] = await redis.scan(0, 'MATCH', 'user:*', 'COUNT', 100);