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.
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>
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 :
- Un cookie nommé PHPSESSID dont la valeur (11d2423i2765aoh3ev5nmj0n76) est cryptée.
- 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).
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
. . .
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
Enregistrer un commentaire