# Migrer le cache de session vers Redis après une panne en centre de formation

> Un module e-learning s'effondre à chaque pic de connexions simultanées. Retour sur une migration du stockage de session PHP par fichiers vers Redis.

- Auteur : WordPress Développement
- Publié le : 2022-01-26
- Mis à jour le : 2022-01-26
- Catégorie : Performance
- URL : https://www.wpmoderne.fr/performance/migration-cache-session-redis-centre-formation/

## L’essentiel

- Le handler de session « files » sature sous la concurrence
- Redis lève le verrou par requête au lieu du fichier
- Le TTL de session doit rester cohérent avec le parcours pédagogique

90 secondes. C'est le temps qu'il fallait, un mardi matin de janvier, à près de deux cents apprenants pour se connecter en même temps à un module de quiz noté avant la fermeture d'une session de formation. Une partie d'entre eux n'y est simplement jamais arrivée : timeout, page blanche, ou pire, une progression de quiz remise à zéro après un rafraîchissement malheureux.

Le diagnostic a mis en évidence un point que beaucoup de configurations WordPress ignorent superbement : le stockage de session PHP natif (`session_start()`), utilisé par le plugin de e-learning pour suivre la progression d'un utilisateur dans un parcours, n'a rien à voir avec le cache d'objets ou les transients WordPress. Il vit sa vie dans `session.save_path`, en général un répertoire de fichiers sur le disque local du serveur applicatif.

## Le handler « files » et ses limites

Par défaut, PHP écrit chaque session dans un fichier séparé (`/var/lib/php/sessions` sous Debian, par exemple) et pose un verrou exclusif sur ce fichier pendant toute la durée du traitement de la requête. Tant que le verrou est actif, toute autre requête du même utilisateur — un appel Ajax de sauvegarde automatique du quiz, un chargement d'image en arrière-plan qui vérifie l'authentification — reste bloquée en attente.

Sur un poste de travail isolé, ce mécanisme est invisible. Sur un module qui déclenche plusieurs appels Ajax concurrents par apprenant (validation de réponse, minuteur, sauvegarde de brouillon), et multiplié par deux cents connexions simultanées, le système de fichiers du serveur devient le vrai goulet d'étranglement : inodes créés en masse, verrous en cascade, et des workers PHP-FPM entiers immobilisés en attente d'un verrou de session au lieu de traiter de nouvelles requêtes.

## Pourquoi Redis change la donne

> L'essentiel à retenir : Le handler de session « files » sature sous la concurrence ; Redis lève le verrou par requête au lieu du fichier ; Le TTL de session doit rester cohérent avec le parcours pédagogique

Redis résout le problème à la racine parce qu'il ne verrouille pas un fichier entier mais une clé, avec un mécanisme de verrouillage optimisé pour la concurrence et une latence d'accès en mémoire plutôt que sur disque. En basculant le handler de session PHP vers Redis, chaque session devient une clé `PHPREDIS_SESSION:<id>` indépendante des autres, ce qui supprime la contention observée sur le système de fichiers.

La bascule s'est faite en modifiant la configuration du pool PHP-FPM dédié au site, sans toucher au code du plugin :

```
; pool.conf ou php.ini du site
php_value[session.save_handler] = redis
php_value[session.save_path] = "tcp://127.0.0.1:6379?auth=motdepasse&timeout;=2.5"
```

Cette configuration suppose que l'extension `redis` pour PHP (PhpRedis) est installée sur le serveur, distincte du client utilisé par un éventuel plugin d'object cache WordPress. Les deux peuvent cohabiter sur la même instance Redis à condition de séparer les bases logiques (`select` 0 et 1, par exemple) pour éviter que le vidage du cache d'objets n'emporte les sessions actives.

## Ce qu'il a fallu vérifier avant la bascule

- La persistance de l'instance Redis : une session perdue en cours de quiz est aussi désagréable qu'un fichier corrompu, il fallait donc activer l'AOF (`appendonly yes`) plutôt que se contenter du snapshot RDB par défaut.
- Le `maxmemory-policy` : une politique `allkeys-lru` aurait pu expulser des sessions actives sous pression mémoire ; le choix s'est porté sur `volatile-lru` avec un TTL explicite posé sur chaque session.
- Le TTL cohérent avec le parcours pédagogique : une session expirée à 30 minutes alors qu'un module de formation dure 45 minutes aurait simplement déplacé le problème.

## Résultats mesurés sur la session suivante

La session de formation suivante a réuni un volume de connexions comparable, avec un suivi via les logs PHP-FPM (champ `%d` du `slowlog`) et un tableau de bord Redis basique (`INFO commandstats`). Le nombre de requêtes en time-out, qui représentait environ 40 % des tentatives de connexion lors de l'incident initial, est retombé à zéro. Le temps de connexion médian est passé de plusieurs dizaines de secondes à moins de 300 millisecondes.

Un effet secondaire bienvenu : la charge CPU du serveur applicatif a également baissé, les workers PHP-FPM n'étant plus mobilisés en attente passive de verrous de fichiers.

### Un point de vigilance : le failover

Avec une seule instance Redis, une coupure du service Redis entraîne la perte immédiate de toutes les sessions actives — chaque apprenant serait déconnecté en pleine évaluation. Une réplique Redis Sentinel a été mise en place dans un second temps, avec bascule automatique et une reconnexion gérée côté PHP par un `timeout` de connexion court et une nouvelle tentative applicative.

> Sur ce type de projet, mieux vaut traiter le stockage de session comme une dépendance critique à part entière, avec sa propre surveillance, plutôt que comme un détail de configuration invisible.

## En résumé

Le stockage de session par fichiers convient parfaitement à un site WordPress classique à trafic modéré. Il devient un vrai risque dès qu'un module métier génère des appels concurrents intensifs par utilisateur, ce qui est précisément le cas d'un parcours e-learning chronométré. Migrer vers Redis a supprimé la contention de verrous, réduit la charge serveur et, surtout, rendu les sessions de formation fiables lors des pics de connexion — sans qu'une seule ligne du plugin pédagogique n'ait eu besoin d'être modifiée.
