creative commons
Répartition de charge et Haute disponibilité sur les OS *BSD (Partie 1)
icone administration-systeme
Signature :
GNU/Linux Magazine
Sommaire de l'article :

1. Avertissement

Il se peut qu'au cours de cet article vos lutins décident de s'envoyer en l'air, GCU ne pourra être tenu responsable de la perte de l'un d'eux. Nous partons du principe que vous avez déjà utilisé PF et nos chers *BSD.

2. Introduction

Toi aussi, tu es en plein leverage de ton architecture middleware pour l'installation de ton nouveau progiciel de e-learning. Alors, pour le déploiement de cette nouvelle application web2.0 compliant tes managers te demandent d'améliorer la Load scalability et, si tu n'y arrives pas, tu vas perdre le leadership de ta team. MAIS, heureusement, tu as lu le dernier 01 et tu as vu les mots LOAD BALANCING et HIGH AVAILABILITY... Eh bien oui, dans cet article nous allons t'apprendre à faire tout ça à l'aide de tes petits doigts et des merveilleux outils que nos barbus de chez *BSD and Co. nous ont mis à disposition. Certes, cela ne va pas provoquer l'effet d'un cululingus sur tes managers, mais je t'assure que tes cheveux vont briller.

3. Les concepts (OUI GERARD, IL FAUT CONCEPTUALISER)

Gérard, je sais que tu te demandes ce qu'est la haute disponibilité. Eh bien, je vais te le dire. C'est un " concept " visant à mettre en œuvre un ensemble de mesures permettant d'améliorer et de garantir une très forte disponibilité du service. L'ensemble des mesures nécessaires à l'amélioration de la garantie de disponibilité passe par des actions au niveau du matériel, du système, du réseau etc. Nous allons nous intéresser à quelques techniques disponibles, grâce aux outils présents sur nos chers systèmes *BSD, visant à améliorer la disponibilité au niveau réseau. La répartition de charge ou load balancing (pour briller en société) est une technique permettant de répartir la charge sur une ferme de serveurs ou sur un pool de serveurs (toujours pour briller en société) et donc toujours dans la continuité. Alors oui, Gérard, tu te demandes, mais à quoi ça sert ? Eh bien, je peux te le dire, ça sert tout simplement à améliorer la disponibilité de ton service : une plus grande résistance aux pannes (ajout et suppression de serveurs à la volée), possibilité de répondre à plus de clients à la fois, etc. Tu vois Gérard, que c'est pas inutile ! Donc Gérard, je t'explique. Pour faire de la répartition de charge, tu peux le faire au niveau de la couche réseau, au niveau de la couche transport ou au niveau de la couche application (dis-moi Gérard, tu as bien écouté les cours de réseaux ou tu me fais des yeux de merlan frit par pur plaisir ?). De plus, la répartition de charge sur tes serveurs peut se faire à l'aide de différents algorithmes : le plus connu est l'algorithme " round robin " aka je balance un coup à l'un un coup à l'autre, aka aussi la balançoire à lutins. Ce qui signifie qu'à chaque connexion, il est probable que tu n'interroges pas le même serveur. Si, pour une raison ou pour une autre, tu dois mettre en œuvre une persistance pour que l'utilisateur tombe sur le même serveur, tu devras utiliser un algorithme de type " hash ". Passons aux choses sérieuses...

4. Les choses sérieuses (part one)

Voilà, Gérard, tu as donc 2 serveurs WEB et tu te dis : " Mais comment je vais pouvoir faire du load balancing sans acheter un boîtier à très très cher ? " Eh bien, Gérard, j'ai la solution ! Je te propose d'utiliser les fonctionnalités de notre magnifique firewall que nous aimons tous c'est-à-dire PF aka Packet Filter, pour ceux qui n'ont pas lu les pages précédentes. Liste des courses avant de commencer :
  • 1 machine avec 2 cartes réseau faisant office de load balancer ;
  • 2 machines avec une carte réseau faisant office de serveur web.

/img-articles/lmhs/29/cc-art-repartchargeHD/fig-1.jpg

Voyons donc à quoi ressemble notre architecture : Nous allons configurer PF pour lui dire de rediriger chaque requête sur un des serveurs :
web = "{ 192.168.0.2 192.168.0.3 }"

rdr pass on $ext_if proto tcp from any to $ext_if \
        port 80 -> $web round-robin
Il suffit de recharger PF pour que ce soit pris en compte.
# pfctl -f /path/to/pf.conf -F nat
Il suffit donc maintenant d'appeler dans ton joli navigateur http://ip_externe_load_balancer/ et, si tu recharges plusieurs fois, tu vas tomber une première fois sur ton serveur 1, l'autre fois sur ton serveur 2. C'est la balançoire qui commence, Gérard ! Notons que ceci est aussi possible avec IPF, mais bon, PF c'est quand même vachement mieux.

5. OUI, MAIS SAI KOI LES ALGORITHMES DISPONIBLES ???? (part two)

Voila Gérard ! Je savais que tu allais me le demander. Eh bien, PF implémente 4 types d'algorithmes pour la répartition de charge :
  • bitmask, algorithme qui se base sur la plage d'adresses IP du pool de serveurs et l'adresse IP du client ;
  • random, algorithme permettant de rediriger chaque connexion de façon aléatoire sur le pool de serveurs ;
  • round-robin, algorithme permettant de rediriger de façon séquentielle chaque connexion ;
  • source-hash, basé sur l'adresse IP du client permettant d'obtenir une persistance : un même client sera toujours redirigé vers le même serveur.
Le seul algorithme qui répartit la charge de façon équitable est l'algorithme round-robin. En effet, si tu as 10 clients qui se connectent et 5 serveurs, chaque serveur recevra 2 connexions, ce qui n'est pas garanti avec les autres. Une subtilité supplémentaire avec les algorithmes random et round-robin. Il est possible de rajouter l'option sticky-address qui permet d'avoir une pseudo-persistance. Le client tombera sur le même serveur tant que PF aura des informations concernant cette session dans ses tables.

6.??Oui, mais, si ça plante ? (part three)

Oui, Gérard, tu as raison, si ça plante ? Eh ben, pour le moment, si un de nos serveurs web est en panne pour une raison ou une autre (par exemple, parce que ton prestataire venu d'une grande SSII ne connaît rien à l'administration, pourtant il est expert !), eh bien, le load balancer (le répartiteur de charge, je te vois venir toi le défenseur de la langue française) continuera à envoyer des demandes à ce serveur. Le service sera donc fortement perturbé, puisqu'une fois sur deux le client tombera sur le mauvais serveur. Mais là encore une fois, Gérard, pour toi, j'ai une solution pas chère et facile à mettre en œuvre. Dans l'article " PF pour les nuls " (quoi tu ne l'as pas lu ????), tu as entendu parler des tables. Je sais que tu n'es pas convaincu de la puissance des tables et pourtant je vais te montrer qu'elles vont nous permettre d'ajouter et de retirer des serveurs à la volée. Voila donc notre architecture un peu plus complexe (je ris) :

/img-articles/lmhs/29/cc-art-repartchargeHD/fig-2.jpg

Commençons par notre configuration PF :
table <web_up> persist {192.168.0.2,192.168.0.3,192.168.0.4}
table <web_down> persist { }

rdr pass on $ext_if proto tcp from any to $ext_if \
        port 80 -> <web_up> round-robin
Le mot persist, quand on déclare une table, est très important, car cela va nous permettre de manipuler cette table même une fois que les règles sont chargées. Il nous suffit de recharger ensuite notre fichier de configuration.
# pfctl -f /path/to/pf.conf -F nat
Je vois bien ton air dubitatif ; tu te dis : " mais ça gère pas le failover toussaaaa, oui mais regarde" !
# pfctl -t web_up -Ts
Et là, ô, magie, tu vois apparaître la liste de tes serveurs qui sont dans le pool " up ". De même, si tu tapes :
# pfctl -t web_down -Ts
Là, normalement, c'est vide ou alors Gérard tu as sauté une étape. Donc, imagine maintenant que tu fasses un contrôle sur tes serveurs (toutes les x minutes, par exemple) et quand le test échoue sur l'un d'entre eux tu l'enlèves de ton pool de serveurs sur lequel les requêtes sont envoyées :
#!/bin/sh

PING="/sbin/ping -c 2 -t 2"

if ! WEB_UP=`pfctl -t web_up -Ts`; then
    echo "la table web_up n'existe pas"
    exit 1
fi

for IP in $WEB_UP; do
    if $PING $IP >/dev/null 2>&1; then
        echo "$IP est up"
    else
        echo "$IP est down"
        pfctl -t web_up -Td $IP >/dev/null 2>&1
    fi
done
Et là, je sais, Gérard, ce que tu te dis : " Oui OK, c'est bien beau, on enlève le serveur du pool up ", mais imaginons que le serveur revient up, il faut que je fasse la manipulation à la main pour le faire revenir dans le pool up. Eh bien, Gérard pourquoi crois-tu qu'on a déclaré 2 tables, une up, une down ? Tout simplement, pour gérer tout ça !
#!/bin/sh

PING="/sbin/ping -c 2 -t 2"

if ! WEB_UP=`pfctl -t web_up -Ts`; then
    echo "la table web_up n'existe pas"
    exit 1
fi

if ! WEB_DOWN=`pfctl -t web_down -Ts`; then
    echo "la table web_down n'existe pas"
    exit 1
fi

for IP in $WEB_UP; do
    if $PING $IP >/dev/null 2>&1; then
        echo "$IP est up"
    else
        echo "$IP est down"
        pfctl -t web_up -Td $IP >/dev/null 2>&1
        pfctl -t web_down -Ta $IP >/dev/null >2>&1
    fi
done

for IP in $WEB_DOWN; do
    if $PING $IP >/dev/null 2>&1; then
        echo "$IP est maintenant up"
        pfctl -t web_down -Td $IP >/dev/null >2>&1
        pfctl -t web_up -Ta $IP >/dev/null 2>&1
    else
        echo "$IP toujours down"
    fi
done
Alors oui, je sais, tu vas me dire qu'un test ping, ça suffit pas ! Tu as bien raison, mais j'ai confiance en toi pour nous coder une série de tests qui vont te permettre de certifier que ton serveur est bien down. Il est donc possible d'ajouter des serveurs ou d'en retirer à la volée, ce qui permet quand tu ajoutes une nouvelle machine dans ton pool de ne pas perturber le service en rechargeant de façon intempestive ta configuration. Je sais ce que tu te dis : " c'est beau ". Oui, ça l'est et j'espère t'avoir convaincu de l'utilité des tables.

7. La honte, il parle de haute disponibilité, mais si son load balancer plante ! (part four)

Je te voyais venir là, tu as vu de suite le point faible de l'architecture ; en effet, si notre load balancer tombe en panne, le service est complètement interrompu. C'est dans ces moments que tu te dis que la vie est bien faite quand même, parce que nos chers amis (barbus) de chez OpenBSD ont pensé à tout. Ils ont développé CARP (Common Address Redundancy Protocol, une alternative libre aux protocoles VRRP, HSRP et FSRP qui sont soumis à des brevets). Donc, comme son nom l'indique et comme tu as pu le deviner, cela va nous permettre de partager une IP " publique " entre 2 machines : un load balancer maître et un load balancer esclave. Comme ça, en cas de défaillance du load balancer maître, le load balancer esclave s'attribuera l'adresse IP " publique " : le service pourra continuer à fonctionner. La liste des courses avant de commencer :
  • 2 load balancer avec 2 cartes réseau ;
  • 3 serveurs avec une carte réseau (chacun, hein !) ;
  • des câbles réseau ;
  • des switchs ;
  • de l'alcool1
  • de la drogue1
  • un truc à manger.
Voilà donc l'architecture que nous allons mettre en place (voir Fig. 3). Donc, dans cet exemple, 10.0.0.0/24 est notre plage d'adresses " publique ", la plage 172.16.0.0/24 étant notre plage d'adresses dite " privée ", sur laquelle nos serveurs sont connectés. Nos 2 load balancers ont donc sur chacune de ces plages une adresse IP réelle (RIP) et une adresse IP virtuelle (VIP) qu'ils vont se partager.

/img-articles/lmhs/29/cc-art-repartchargeHD/fig-3.jpg

LB1 (Load Balancer maître) possède :
  • l'adresse IP " publique " : 10.0.0.10 (fxp0) ;
  • l'adresse IP " privée " : 172.16.0.10 (fxp1)
LB2 (Load Balancer esclave) possède :
  • l'adresse IP " publique " : 10.0.0.11 (fxp0) ;
  • l'adresse IP " privée " : 172.16.0.11 (fxp1)
Côté réseau " public ", la VIP partagée sera 10.0.0.250. Côté réseau " privé ", la VIP partagée sera 172.16.0.250. Alors Gérard, tu peux te demander pourquoi, côté réseau privé, nous avons besoin d'une VIP : tout simplement parce que nos load balancers font aussi office de passerelles pour nos serveurs. Il faut donc que l'adresse IP de la passerelle ne change pas pour que les serveurs puissent continuer à communiquer vers l'extérieur. Configurons CARP sur LB1 :
 # ifconfig carp0 create
# ifconfig carp1 create 

# ifconfig carp0 vhid 1 advskew 1 \
        pass insère_ici_un_password 10.0.0.250
# ifconfig carp1 vhid 2 advskew 1 \
        pass insère_ici_un_autre_password 172.16.0.250
Configurons CARP sur LB2 :
# ifconfig carp0 create
# ifconfig carp1 create 

# ifconfig carp0 vhid 1 advskew 100 \
        pass insère_ici_un_password 10.0.0.250
# ifconfig carp1 vhid 2 advskew 100 \
        pass insère_ici_un_autre_password 172.16.0.250
Tu as sans doute remarqué la différence de valeur entre LB1 et LB2 pour la directive advskew. Cela nous permet de dire que LB1 sera le maître par rapport à LB2 ; il aura donc la priorité sur LB2. Notons aussi que insère_ici_un_password et insère_ici_un_autre_password doivent être identiques sur les 2 machines. Il faut penser à activer le mode preempt aussi.
# sysctl -w net.inet.carp.preempt=1
La définition du mode preempt et de advskew est très importante pour permettre à LB1 de redevenir maître, sinon, en cas de défaillance de celui-ci, LB2 gardera la main indéfiniment, jusqu'à que ce tu fasses la manipulation nécessaire pour que LB1 redevienne maître. Alors que là, c'est automatique. Si ! Notons aussi, qu'au besoin, il faut autoriser le protocole CARP sur ton firewall :
pass quick on fxp0 proto carp keep state
pass quick on fxp1 proto carp keep state
À rajouter dans ton pf.conf.

8. Oui, mais ! (part five)

Je te vois, Gérard, tu es en train de te dire : " OUI, MAIS SI LB1 PLANTE, OK, LB2 PREND LA MAIN, MAIS IL A TOUT PERDU ET DONC SAI NUL. " Encore une fois, Gérard, j'ai envie de te dire : " tais-toi ". Les barbus (ils font forts ces barbus !) ont pensé à tout. Ils ont mis à ta disposition un joli petit jouet qui s'appelle Pfsync. Pfsync est un pseudo device réseau qui se charge d'ausculter les changements d'état du firewall et de les envoyer sur le réseau. Par défaut, Pfsync fait du multicast et sans authentification. C'est pourquoi, il est préférable d'utiliser un réseau séparé pour éviter qu'un gentil pirate ne déclare aussi son Pfsync. Notons qu'il existe l'option syncpeer permettant de spécifier à Pfsync d'envoyer en unicast à un seul serveur Pfsync (améliorant ainsi la sécurité). Donc, on reprend la même architecture que tout à l'heure et on l'améliore :

/img-articles/lmhs/29/cc-art-repartchargeHD/fig-4.jpg

Par rapport à tout à l'heure nous avons rajouté 1 carte réseau sur chaque load balancer : ils ont donc un réseau dédié pour les échanges pfsync. Configurons LB1 :
# ifconfig fxp2 192.168.0.1 netmask 255.255.255.0
# ifconfig pfsync0 syncdev fxp2
# ifconfig pfsync0 up
Configurons LB2 :
# ifconfig fxp2 192.168.0.2 netmask 255.255.255.0
# ifconfig pfsync0 syncdev fxp2
# ifconfig pfsync0 up
Au besoin, il faut autoriser le protocole Pfsync sur ton firewall :
pass quick on fxp2 proto pfsync
... dans ton pf.conf.

9. Oh oui, j'en veux encore ! (part six)

Gérard, tu es gourmand, mais j'aime ça. Ta soif de connaissance me plaît. Je vais maintenant te parler d'une nouvelle technique : interface bonding (rien à voir avec le bondage Gérard, tu as vraiment l'esprit mal placé) ou agrégation d'interface. Je vois bien tes yeux briller Gérard. Cette technique te permet tout simplement de faire l'agrégation de 2 liens réseau, ce qui offre une grande tolérance aux pannes. En effet, si un lien réseau tombe, le reste du trafic bascule vers l'autre lien réseau. Voilà la liste des courses :
  • 2 load balancers avec 4 interfaces réseau ;
  • 2 serveurs avec 2 interfaces réseau ;
  • 4 switchs ;
  • des câbles réseau ;
  • une photo de Pinpin ;
  • de l'alcool1 ;
  • de la drogue1 ;
  • un truc à manger (ce que tu veux : un chien chaud, du chat, du rat, etc.).
Voyons à quoi ressemble notre architecture :

/img-articles/lmhs/29/cc-art-repartchargeHD/fig-5.jpg

De cette façon, nous avons une forte tolérance aux pannes, puisque, si un de nos switchs tombe en panne, il est redondé et donc le " chemin " réseau n'est jamais rompu. Configurons les agrégats sur LB1 :
# ifconfig fxp0 up
# ifconfig fxp1 up
# ifconfig trunk0 trunkproto failover \
        trunkport fxp0 trunkport fxp1 \
        10.0.0.10 netmask 255.255.255.0

# ifconfig fxp2 up
# ifconfig fxp3 up
# ifconfig trunk1 trunkproto failover \
        trunkport fxp2 trunkport fxp3 \
        172.16.0.10 netmask 255.255.255.0
Gérard tu as donc compris que trunk0 est l'agrégat de l'interface fxp0 et fxp1 et que trunk1 est l'agrégat de fxp2 fxp3. Le mot clé failover permet de spécifier que l'ensemble du trafic passera par fxp0 et, en cas de défaillance de ce lien, le trafic passera par fxp1. De même, avec avec fxp2 et fxp3. Configurons les agrégats sur LB2 :
# ifconfig fxp0 up
# ifconfig fxp1 up
# ifconfig trunk0 trunkproto failover \
        trunkport fxp0 trunkport fxp1 \
        10.0.0.11 netmask 255.255.255.0

# ifconfig fxp2 up
# ifconfig fxp3 up
# ifconfig trunk1 trunkproto failover \
        trunkport fxp2 trunkport fxp3 \
        172.16.0.11 netmask 255.255.255.0
Et ainsi de suite... Il ne te reste plus qu'à appliquer l'ensemble des techniques que tu as vues tout au long de cet article sur tes nouvelles interfaces virtuelles. Note Gérard que cette manipulation n'est possible qu'à partir d'OpenBSD 3.9.

Pour conclure

Voilà, si tu n'as pas compris quelque chose dans cet article, je n'ai qu'une chose à te dire : " RTFM ". Ah oui, Gérard, tu es invité à mon mariage avec Spud. Pour les sources d'informations : http://openbsd.org/faq/pf/ http://openbsd.org/faq/faq6.html#CARP http://www.countersiege.com/doc/pfsync-carp/ http://team.gcu-squad.org/~aflab/papers/ http://www.gcu.info/
Il y a : 0 commentaire(s)

Donnez votre avis

Vous devez avoir ouvert une session pour écrire un commentaire.

Brèves
Édito : Linux Pratique Essentiel N°24
Édito : Linux Pratique HS N°23
Édito : GNU/Linux Magazine 146
Édito : GNU/Linux Magazine HS N°58
Édito : Open Silicium N°5
Communication
Linux Pratique HS 23 – Communiqué de presse
Linux Pratique Essentiel N°24 – Communiqué de presse
Gnu/Linux Magazine sponsor et partenaire de PROLOGIN
Linux Essentiel partenaire des Rencontres du Libre de Lion sur Mer (Normandie)
GNU/Linux Magazine HS 58 – Communiqué de presse
prochainement moteur de recherches des articles
 
:
:
Jours heures minutes secondes
En kiosque
Le tout nouveau Linux Pratique Essentiel est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau Linux Pratique est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau GNU/Linux Magazine est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau GNU/Linux Magazine HS est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau Open Silicium est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau Linux Pratique est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau Misc est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...

Le tout nouveau GNU/Linux Magazine est disponible dès maintenant chez votre marchand de journaux et sur notre site...

Lire la suite...