Apres avoir migre de Redis vers KeyDB puis de nouveau vers Redis tout en traitant des milliards en transactions logistiques, j'ai appris quels patterns Redis fonctionnent a grande echelle. Voici 5 patterns eprouves que vous pouvez implementer aujourd'hui.
1. Pipeline tout (gain de performance 10x)
Mauvais pattern :
// Ceci cree 1000 allers-retours reseau !
foreach ($shipments as $shipment) {
Redis::set("shipment:{$shipment->id}", $shipment->toJson());
Redis::expire("shipment:{$shipment->id}", 3600);
}Pattern production :
// Un seul appel reseau, execution atomique
Redis::pipeline(function ($pipe) use ($shipments) {
foreach ($shipments as $shipment) {
$pipe->setex(
"shipment:{$shipment->id}",
3600,
$shipment->toJson()
);
}
});Impact reel : Nous avons reduit notre temps d'import en masse de 45 secondes a 4 secondes pour 10k enregistrements.
2. Implementer le Rate Limiting a fenetre glissante
Oubliez les fenetres fixes qui causent des rafales de requetes. Voici ce que nous utilisons en production :
class RateLimiter
{
public static function attempt($key, $max = 60, $decay = 60)
{
$key = "rate_limit:{$key}";
$now = microtime(true);
$window = $now - $decay;
Redis::pipeline(function ($pipe) use ($key, $now, $window, $max) {
// Supprimer les anciennes entrees
$pipe->zremrangebyscore($key, 0, $window);
// Ajouter la requete actuelle
$pipe->zadd($key, $now, $now);
// Compter les requetes dans la fenetre
$pipe->zcard($key);
// Definir l'expiration
$pipe->expire($key, $decay + 1);
});
$results = $pipe->execute();
$count = $results[2];
return $count <= $max;
}
}
// Utilisation dans un middleware
if (!RateLimiter::attempt("api:{$request->ip()}", 100, 60)) {
return response('Rate limit exceeded', 429);
}Pourquoi ca marche : Pas de pics aux limites de fenetre, distribution equitable, auto-nettoyage.
3. Invalidation de cache avec tags (la bonne methode)
Les tags de cache Laravel sont genials jusqu'a ce que vous ayez besoin d'un controle granulaire. Voici notre pattern :
class SmartCache
{
public static function rememberWithDependencies($key, $tags, $ttl, $callback)
{
// Stocker le cache principal
$value = Cache::remember($key, $ttl, $callback);
// Suivre les dependances dans des sets Redis
Redis::pipeline(function ($pipe) use ($key, $tags) {
foreach ($tags as $tag) {
$pipe->sadd("cache_tag:{$tag}", $key);
$pipe->expire("cache_tag:{$tag}", 86400); // 1 jour
}
});
return $value;
}
public static function invalidateTag($tag)
{
$keys = Redis::smembers("cache_tag:{$tag}");
if (!empty($keys)) {
// Supprimer toutes les cles taguees en un seul pipeline
Redis::pipeline(function ($pipe) use ($keys, $tag) {
foreach ($keys as $key) {
$pipe->del($key);
}
$pipe->del("cache_tag:{$tag}");
});
}
}
}
// Utilisation
$metrics = SmartCache::rememberWithDependencies(
'dashboard.metrics',
['shipments', 'deliveries', "customer:{$customerId}"],
300, // 5 minutes
fn() => $this->calculateExpensiveMetrics()
);
// Invalider tous les caches lies aux expeditions
SmartCache::invalidateTag('shipments');Victoire en production : Reduction des cache misses de 73% et elimination des invalidations en cascade.
4. Verrous distribues qui ne deadlock pas
Apres avoir perdu 50k$ a cause d'une race condition, nous avons implemente ce verrouillage a toute epreuve :
class DistributedLock
{
public static function acquire($resource, $timeout = 10)
{
$lockKey = "lock:{$resource}";
$identifier = uniqid(gethostname(), true);
// Set atomique si n'existe pas avec expiration
$acquired = Redis::set(
$lockKey,
$identifier,
'NX', // Seulement si n'existe pas
'EX', // Expire apres X secondes
$timeout
);
if ($acquired) {
return $identifier;
}
// Verifier si le verrou est obsolete (mecanisme de secours)
$lockHolder = Redis::get($lockKey);
if (!$lockHolder) {
// Le verrou a expire entre les commandes, reessayer
return self::acquire($resource, $timeout);
}
return false;
}
public static function release($resource, $identifier)
{
$lockKey = "lock:{$resource}";
// Script Lua pour verification et suppression atomique
$script = "
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
";
return Redis::eval($script, 1, $lockKey, $identifier);
}
public static function withLock($resource, $callback, $timeout = 10)
{
$identifier = self::acquire($resource, $timeout);
if (!$identifier) {
throw new LockTimeoutException("Could not acquire lock for {$resource}");
}
try {
return $callback();
} finally {
self::release($resource, $identifier);
}
}
}
// Utilisation pour le traitement des paiements
DistributedLock::withLock("payment:{$invoice->id}", function () use ($invoice) {
// Traiter le paiement en securite
if ($invoice->isPaid()) {
return; // Verification idempotente
}
$invoice->processPayment();
$invoice->markAsPaid();
});Critique : Le script Lua garantit que nous ne liberons que NOTRE verrou, empechant la liberation accidentelle du verrou de quelqu'un d'autre.
5. Metriques temps reel avec HyperLogLog
Suivez les visiteurs/evenements uniques sans explosion de memoire :
class MetricsTracker
{
public static function trackUnique($metric, $identifier, $window = 3600)
{
$key = "metric:{$metric}:" . floor(time() / $window);
// HyperLogLog ajoute des elements uniques avec espace O(1)
Redis::pfadd($key, $identifier);
Redis::expire($key, $window * 2); // Garder 2 fenetres
return Redis::pfcount($key);
}
public static function getCardinality($metric, $windows = 1, $windowSize = 3600)
{
$keys = [];
$now = time();
for ($i = 0; $i < $windows; $i++) {
$keys[] = "metric:{$metric}:" . floor(($now - ($i * $windowSize)) / $windowSize);
}
// Fusionner plusieurs HyperLogLogs
return Redis::pfcount($keys);
}
public static function trackAndBroadcast($event, $userId)
{
// Suivre l'evenement unique
$count = self::trackUnique("event:{$event}:users", $userId);
// Suivre le taux par minute
$rate = self::trackUnique("event:{$event}:rate", uniqid(), 60);
// Diffuser si seuil atteint
if ($rate > 1000) {
broadcast(new HighTrafficAlert($event, $rate));
}
return $count;
}
}
// Utilisation
$uniqueVisitors = MetricsTracker::trackUnique('page.visits', $request->ip());
$dailyActive = MetricsTracker::getCardinality('user.active', 24, 3600);
// Suivre l'utilisation API sans problemes de memoire
MetricsTracker::trackAndBroadcast('api.call', $user->id);Economies de memoire : Suivre 10M d'utilisateurs uniques prend ~12KB au lieu de 40MB avec les sets traditionnels.
Bonus : Checklist d'optimisation memoire Redis
De notre playbook production :
// 1. Utiliser la compression pour les grandes valeurs
Redis::setex(
"large:{$id}",
3600,
gzcompress(json_encode($data), 9)
);
// 2. Utiliser les hashes pour les petits objets (90% d'economie memoire !)
Redis::hset("user:{$id}", [
'name' => $user->name,
'email' => $user->email,
'status' => $user->status
]);
// 3. Definir des expirations agressives
Redis::setex($key, 300, $value); // 5 min par defaut, pas 1 heure
// 4. Utiliser SCAN au lieu de KEYS
$cursor = 0;
do {
[$cursor, $keys] = Redis::scan($cursor, 'MATCH', 'shipment:*', 'COUNT', 100);
// Traiter $keys
} while ($cursor !== 0);
// 5. Surveiller l'utilisation memoire
$info = Redis::info('memory');
if ($info['used_memory'] > 1073741824) { // 1GB
alert("Redis memory critical: {$info['used_memory_human']}");
}Les lecons couteuses
- Toujours definir des expirations - Un TTL manquant a consomme 8GB de RAM
- Pipeline ou perir - La latence reseau s'accumule vite
- Utiliser la bonne structure de donnees - HyperLogLog nous a fait economiser 2k$/mois en memoire
- Verrouiller correctement - Les race conditions dans les systemes financiers = proces
- Tout surveiller - Vous ne pouvez pas corriger ce que vous ne mesurez pas
Ces patterns gerent 50k requetes/seconde en production. Commencez avec les pipelines et le verrouillage correct - ils resoudront 80% de vos problemes de performance Redis.
Maitriser Laravel avec des projets reels
Vous voulez implementer ces patterns Redis dans une vraie application ? Construisez des projets Laravel prets pour la production a partir de zero :
- Construire un blog avec Laravel - Maitriser Eloquent, l'authentification et les operations CRUD avec le cache Redis
- Construire un portfolio avec Laravel - Apprendre les uploads de fichiers, les relations et les sessions alimentees par Redis
- Construire un e-commerce avec Laravel - Patterns avances incluant les queues, la gestion des evenements et les verrous distribues
Chaque tutoriel inclut des prompts assistes par IA pour vous guider dans la construction d'applications scalables qui utilisent Redis efficacement.
Des questions sur l'implementation de ces patterns ? Laissez un commentaire - j'ai probablement deboggue ce probleme a 3h du matin.
Fred
AUTHORFull-stack developer with 10+ years building production applications. I write about cloud deployment, DevOps, and modern web development from real-world experience.
Need a developer who gets it?
POC builds, vibe-coded fixes, and real engineering. Let's talk.
Hire Me →
