Un client fait remonter un comportement erratique et difficile à reproduire : certains visiteurs se retrouvent déconnectés de leur compte en plein milieu de leur navigation, sans raison apparente, tandis que d’autres ne rencontrent jamais ce problème. Après analyse des journaux d’accès, le point commun apparaît : les visiteurs affectés sont ceux dont les requêtes successives ont été traitées par des serveurs applicatifs différents au sein du pool derrière le répartiteur de charge.
La cause est classique sur une architecture multi-serveurs mise en place sans y penser explicitement : le handler de session par défaut de PHP écrit les fichiers de session dans un répertoire local à chaque machine (généralement /var/lib/php/sessions), invisible depuis les autres serveurs. Un visiteur connecté via le serveur A, dont la requête suivante atterrit sur le serveur B, se retrouve traité comme s’il n’avait jamais de session ouverte.
Pourquoi le fichier local ne suit pas la charge répartie
PHP gère nativement les sessions via un identifiant transmis dans un cookie au navigateur, et stocke les données associées à cet identifiant sur le disque local du serveur qui a traité la requête. Cette approche fonctionne parfaitement sur un serveur unique, mais s’effondre dès qu’un deuxième serveur applicatif entre dans l’équation sans partage explicite de cet espace de stockage.
; php.ini par défaut, session en fichier local
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
Première option : partager le répertoire de fichiers
Une approche minimaliste consiste à monter un espace de stockage réseau partagé (NFS notamment) accessible depuis tous les serveurs applicatifs, pour que le répertoire de sessions soit physiquement le même partout. Cette solution fonctionne mais introduit une dépendance de latence réseau à chaque lecture et écriture de session, et un point de panne supplémentaire si le stockage réseau devient indisponible.

Deuxième option : Redis comme backend de session
L’option retenue sur ce projet a été de centraliser les sessions dans une instance Redis dédiée, accessible en réseau interne depuis chaque serveur applicatif, avec un temps de réponse en mémoire bien plus rapide qu’un partage de fichiers réseau.
; php.ini, redirection des sessions vers Redis
session.save_handler = redis
session.save_path = "tcp://10.0.0.20:6379?auth=motdepasse-fort&database;=1"
Chaque serveur applicatif pointe vers la même instance Redis, identifiée par son adresse réseau interne, avec une base numérotée dédiée aux sessions (ici la base 1) pour la séparer clairement de tout autre usage éventuel de la même instance Redis.
Un point de vigilance : Redis pour les sessions, pas pour le cache d’objets
Ce sujet des sessions PHP centralisées ne doit pas être confondu avec le cache d’objets Redis de WordPress, traité par ailleurs côté performance sur ce blog : même si les deux usages peuvent techniquement partager la même instance Redis physique, il est recommandé de les séparer par numéro de base ou par instance distincte, pour éviter qu’une purge de cache d’objets n’affecte accidentellement les sessions actives des visiteurs, ou inversement.
| Approche | Latence | Point de panne supplémentaire |
|---|---|---|
| Fichier local (défaut) | Très faible, mais non partagé | Aucun, mais ne fonctionne pas en multi-serveur |
| Fichier sur stockage réseau (NFS) | Moyenne, dépend du réseau | Le serveur de stockage réseau |
| Redis centralisé | Faible, accès mémoire | L’instance Redis elle-même |
Rendre Redis lui-même hautement disponible
Centraliser les sessions sur une seule instance Redis déplace le point de panne unique plutôt que de le supprimer : si cette instance tombe, tous les visiteurs de tous les serveurs perdent leur session simultanément, un risque plus large qu’avant la centralisation. Sur ce projet, une réplication Redis avec bascule automatique via Sentinel a été mise en place pour éviter que ce nouveau point central ne devienne lui-même une source de panne globale.
- Une instance Redis principale et au moins une instance réplica, avec Redis Sentinel pour la détection de panne et la promotion automatique.
- Un délai d’expiration de session cohérent avec la politique du site (durée de connexion souhaitée côté utilisateur).
- Une surveillance de la mémoire utilisée par Redis, pour éviter qu’une accumulation de sessions non expirées ne sature l’instance.
Centraliser un état partagé entre plusieurs serveurs résout un problème de cohérence mais en crée un nouveau, de disponibilité : le vrai travail ne s’arrête jamais à la simple redirection vers Redis, il continue par la mise en haute disponibilité de Redis lui-même.
Résultat mesuré après mise en place
Avant la centralisation, un échantillon d’une semaine de journaux avait révélé qu’environ 15 % des sessions actives présentaient une perte de connexion inexpliquée, corrélée aux changements de serveur applicatif traitant les requêtes successives d’un même visiteur. Après bascule vers Redis comme backend de session, ce taux est retombé à un niveau résiduel proche de zéro, correspondant uniquement aux expirations normales de session.
En résumé
Sur une architecture WordPress répartie sur plusieurs serveurs applicatifs, les sessions PHP en fichier local sont une source quasi certaine de déconnexions aléatoires, invisible tant que le trafic reste sur un seul serveur. Basculer vers Redis comme backend de session centralisé règle ce problème de cohérence, à condition de traiter Redis lui-même comme un composant critique nécessitant sa propre haute disponibilité, distinct de tout usage parallèle en cache d’objets.