Gérer les locks sur les sessions PHP

Tanguy Dechiron

Les problèmes de session en PHP sont assez rares, il peut toutefois arriver que l'on ait des soucis de latence élevée sur son application, et le mécanisme des sessions PHP peut en être la cause.


Comprendre le fonctionnement des sessions en PHP

Côté code, c'est plutôt simple, il suffit de lancer la session avec session_start() puis on peut enregistrer / récupérer les variables que l'on souhaite stocker dans le tableau associatif $_SESSION.

<?php

    // Démarrage de la session
    session_start();

    // Par exemple après une authentification réussie:
    $_SESSION['username'] = $auth_username;

A partir de là un cookie de session est créé dans le navigateur de l'utilisateur, qui lui permettra de récupérer sa session en cours auprès du serveur.

En général, on n'a pas besoin d'en savoir plus pour utiliser les sessions, mais nous allons nous intéresser à ce qui se passe réellement au niveau du serveur.


Lors de la création de la session, un fichier (unique par session) est créé dans le répertoire session.save_path de la configuration PHP (la fonction session_save_path() permet de l'afficher).

Toutes informations liées à la session seront stockées dans ce fichier, et pour ce faire PHP va ouvrir ce fichier en lecture et écriture, et verrouiller son accès. C'est ce dernier point qu'il est intéressant à connaitre et qui peut causer des problèmes de latence.


L'origine du problème et comment y remédier

Comme nous l'avons vu précédemment, le fichier de session est verrouillé pour un script PHP à partir de la commande session_start(). Cela signifie que le fichier de session ne sera disponible que lorsque le script sera terminé.

Le problème survient dans 2 cas de figure:

  • une application backend sur laquelle on est authentifié, qui rame pour un traitement très long, on ouvre un autre onglet mais impossible d'accéder à l'application
  • une application qui utilise des appels ajax vers le backend et ceux-ci s'exécutent les uns après les autres, si certains traitement sont longs cela impacte l'ensemble des appels asynchrones.

Cela est tout simplement dû au fait que lorsqu'un second appel est fait sur la même session, il doit attendre que le premier soit terminé pour pouvoir accéder au fichier de session...


La solution ad hoc

Lorsque l'on est dans une application legacy, et que la refactorisation est difficile voire impossible, la solution la plus simple est d'utiliser la fonction session_write_close() afin de fermer l'accès au fichier de session.

Il conviendra de placer cette méthode APRES que l'on écrive dans le fichier de session et AVANT le traitement qui prend du temps.

Car si on la met avant d'écrire en session on écrira dans le vide 😅

<?php
    // Démarrage de la session
    session_start();

    // Par exemple après une authentification réussie:
    $_SESSION['username'] = $auth_username;

    // Libère le fichier de session pour les appels suivants / concurrents
    session_write_close();

    // Traitement qui prend du temps (requêtes, etc.)
    ...

Cette solution est plus un patch qu'autre chose, à réserver donc à une application existante avec beaucoup de code legacy.


Autres solutions - plus élégantes et durables
Paralléliser les tâches

Une solution plus intéressante est d'utiliser un système de Message Queuing permettant de paralléliser les traitements lourds, afin de les exécuter en arrière plan.

Avec Symfony on peut utiliser Messenger, mais également utiliser en plus une solution comme RabbitMQ, Kafka, etc.

Cela demande un peu de travail en amont de conception, mais apportera beaucoup de scalabilité à l'application.


Authentification par token

Enfin, surtout pour des applications qui ont un front dédié (par exemple en React ou VueJS) et dont le backend est une pure API, remplacer les sessions par un système d'authentication en Token Bearer avec JWT.

La plupart des frameworks le prennent en charge, avec Symfony c'est assez simple il faut activer l'Access Token Authentication.


Malgré leurs défauts j'aime bien les sessions 😉 j'ai tendance à privilégier dans mes développements la simplicité et l'efficacité.



A propos de l'auteur

Tanguy Dechiron

Tanguy Dechiron

Développeur web fullstack (Symfony++).
Passionné de littérature fantasy, jeux de société.
Cycliste du dimanche.


Blog Comments powered by Disqus.