Affinité de session et PHP

Dans l'article intitulé "L'affinité de session  avec ClusterHAT", nous avons vu comment configurer HaProxy pour implémenter l'affinité de session. C'est à dire, à maintenir un cookie de session valable tout au long de la navigation sur le site dans le cas où plusieurs serveurs différents peuvent répondre en équilibrage de charge.
Lorsque l'internaute  arrive sur la première page du site, HaProxy, tel qu'il est configuré crée un cookie nommé CLUSTER auquel il donne la valeur Z1, Z2 ou Z3 en fonction du serveur qui répond. Cela permet d'implémenter l'afinité de session. Or, de son coté, PHP a créé un cookie de session nommé PHPSESSID auquel est associée un objet session manipulé en PHP par la variable globale $_SESSION. Or, ces deux cookies ont le même rôle.
L'objet du présent article est d'utiliser le cookies de PHP pour implémenter l'affinité de session.

Description du problème

Afin de mettre en évidence le problème nous allons faire une modification dans page1.php pour afficher tous les cookies créés.

Contenu de page1.php

<?php
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
        <title>Page 1</title>
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
        <meta name="generator" content="Geany 1.29" />
</head>

<body>
        <h1>Page 1</h1>
        <h2>Quel est le serveur qui répond ?</h2>
        <h3>
<?php
$hostaddress = $_SERVER['SERVER_ADDR'];
$hostname = gethostbyaddr($hostaddress);
echo "Réponse provenant de $hostname ( $hostaddress )";
?>
        </h3>
        <h2>Liste des cookies</h2>
        <table border="1">
                <tr><th>Clef</th><th>Valeur</th></tr>
<?php
foreach ($_COOKIE as $key=>$value)
{
    echo "<tr><td>$key</td><td>$value</td></tr>";
}
?>
        </table>
        <h2>Variables de session</h2>
        <table border="1">
                <tr><th>Clef</th><th>Valeur</th></tr>
<?php
foreach ($_SESSION  as $key=>$value)
{
    echo "<tr><td>$key</td><td>$value</td></tr>";
}
?>
        </table>
</body>

</html>
Lorsqu'après avoir chargé dans le navigateur la page session.php, puis cliqué le lien vers la page 1, le contenu ci-dessous s'affiche :
On constate que deux cookies ont été créés :
  1. Un cookie nommé PHPSESSID dont la valeur (11d2423i2765aoh3ev5nmj0n76) est cryptée. 
  2. Un cookie nommé CLUSTER (c'est le nom du cookie de session défini dans /etc/haproxy/haproxy.cfg) dont la valeur est Z3 (valeur définie pour le serveur slave03  qui a répondu dans /etc/haproxy/haproxy.cfg).
Or ces deux cookies sont lié au même concept. L'un est initialisé par PHP et permet d'y associer un objet session, l'autre est initialisé par HaProxy pour gérer l'équilibrage de charge et l'affinité de session. Ce serait plus rigoureux n'en avoir qu'un seul qui fait le tout.

Modification de la configuration de HaProxy 

Ce qui vient en premier à l'esprit c'est de remplacer dans /etc/haproxy/haproxy.cfg le nom du cookie (CLUSTER) par celui du cookie de session de PHP (PHPSESSID).  Il n'y aurait plus qu'un seul cookie (PHPSESSID) mais la valeur de celui-ci serait alors Zx, ou x est le numéro du serveur qui a répondu. L'affinité de session et l'équilibrage de charge sont bien implémentés. Mais on risque fort de ne pas retrouver les valeurs enregistrées dans l'objet $_SESSION puisque la référence crypté de PHP est perdue.

Une petite modification dans le fichier /etc/haproxy/haproxy.cfg va permettre de résoudre le problème :
. . .
backend Web-nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    option httpchk HEAD / HTTP/1.1\r\nHost:localhost
#     cookie CLUSTER insert nocache
    cookie PHPSESSID prefix nocache
    server Pi-Zero-01 slave01:8080 cookie Z1 check
    server Pi-Zero-02 slave02:8080 cookie Z2 check
    server Pi-Zero-03 slave03:8080 cookie Z3 check
. . .

Au lieu de la commande insert, on utilise la commande prefix. La valeur du cookie utilisée pour l'affinité de session donnée par HaProxy n'est plus Zx, mais Zx suivi de la chaîne cryptée de PHPSESSID (Z1~don0cf9ijafefm7p2k93eubcd2 dans l'exemple ci-dessous). Cependant dans PHP, la valeur du cookie est toujours la chaîne cryptée qui permet de référencer l'objet $_SESSION.
Comme souhaité, il n'y a plus qu'un seul cookie, celui de PHP. Et l'équilibrage de charge et  l'affinité  de session sont préservés.

Remarque

Dans cet article, le nom du cookie utilisé PHPSESSID est celui de PHP, le langage serveur utilisé en exemple pour ClusterHAT. Mais  il existe le même concept pour TomCat-Java, et IIS-ASP.NET et d'autres serveurs d'application.
Par exemple, pour TomCat, le nom du cookie est JSESSIONID et pour ASP.NET, le nom du cookie est ASP.NET_SessionId.

Commentaires

Posts les plus consultés de ce blog

Gérer la mise en veille

Configurer VSCode pour programmer et déboguer à distance sur Raspberry Pi

Créer un nouvel utilisateur Raspbian