Activité Répartition de charge et basculement

Consigne

Avant de commencer, veuillez lire une première fois le document dans son ensemble.

Le travail est individuel. Vous pouvez communiquer en respectant le code d’honneur. Si vous être bloqué, demandez de l’aide afin de ne pas prendre trop de retard.

Situation

Vous êtes un administrateur de base de données. Vous devez assurer une haute disponibilité pour un service, y compris en cas de panne d’un serveur. Dans ce but, vous avez mis en place une réplication primary-primary de manière à pouvoir basculer sur l’autre serveur en cas de panne du serveur actif et la reprise après panne du serveur défaillant. En l’état, le basculement est manuel. Vous décidez maintenant d’automatiser le basculement à l’aide de Keepalived.

Objectifs

À la fin de cette activité, vous devez :

  • Connaître la différence entre basculement et répartition de charge.
  • Connaître des outils permettant d’effectuer un basculement en cas de panne (failover).
  • Connaître des outils permettant de distribuer la charge entre plusieurs serveurs.
  • Connaître des outils spécialisés pour MariaDB.
  • Être capable de configurer Keepalived
  • Être capable de configurer Haproxy

Résultat attendu

Deux serveurs MariaDB configurés en miroir et keepalived installé sur chacun d’eux.

Un rapport qui retrace les différentes étapes de la configuration et du processus de promotion du serveur secondaire en serveur primaire après la panne.

Ressources

Matériel :

  • Une machine « svr-m140-$NUM-sql.lab.epai-ict.ch ».
  • Une machine « svr-m140-$NUM-sql-01.lab.epai-ict.ch »
  • Une machine « svr-m140-$NUM-sql-02.lab.epai-ict.ch »

La variable « $NUM » est le numéro de votre réseau tel qu’il apparait dans les informations d’identification que vous avez reçues par courriel.

Mise en route

Grappe de serveurs

Une grappe de serveurs (cluster) est un groupe d’ordinateurs reliés en réseau et qui travaillent ensemble pour fournir un service et conçu de telle manière qu’elle apparait sur le réseau comme un seul hôte. Une grappe de serveur est souvent mise en œuvre pour améliorer la disponibilité (availability) d’un service, pour améliorer l’évolutivité (scalability) d’un service en facilitant sa mise à l’échelle (scaling), ou les deux.

Avant de voir comment réaliser une grappe de serveur, arrêtons-nous un instant sur les notions de haute disponibilité et de mise à l’échelle.

Haute disponibilité

La haute disponibilité fait référence à la capacité d’un service à rester fonctionnel et accessible en continu, même si un serveur est arrêté à cause d’une défaillance matérielle ou logicielle, ou pour des tâches de maintenance. Il s’agit d’assurer un temps de fonctionnement maximal pour des services critiques (applications, bases de données, annuaires, etc.).

Dans un contrat de service, la disponibilité est généralement représentée par un pourcentage. Par exemple, une disponibilité de 90% autorise jusqu’à 36.5 jours d’interruption par an. Le pourcentage est souvent exprimé par un nombre de «neufs». Une disponibilité de 90% se dit «un neuf», une disponibilité de 99% se dit «deux neufs», 99.9% «trois neufs», et ainsi de suite. Une disponibilité de «cinq neufs» assure moins de 5.26 minutes d’interruption par an.

Pour atteindre la haute disponibilité, un système informatique est conçu avec des composants redondants: équipements réseau, disques (RAID), serveurs, etc., afin de garantir qu’aucun point de défaillance unique (single point of failure ou SPOF) ne puisse compromettre l’ensemble du système. La redondance des serveurs est souvent réalisée avec des grappes de serveur.

Mise à l’échelle

La mise à l’échelle (scaling) d’un service désigne l’augmentation de la capacité de traitement de ce service. Elle peut être réalisée de deux manières :

  • La mise à l’échelle verticale (vertical scaling) consiste à augmenter la capacité de traitement d’un service en augmentant la puissance de l’ordinateur qui l’héberge par l’ajout de CPU, de mémoire, d’adaptateurs réseau, etc.
  • La mise à l’échelle horizontale (horizontal scaling) consiste à distribuer la charge de travail entre plusieurs ordinateurs. L’ajout d’ordinateurs permet d’augmenter la capacité de traitement.

La mise à l’échelle horizontale à l’aide d’une grappe de serveur est particulièrement souple et s’applique bien à des charges de travail qui ne modifie pas l’état interne des serveurs. Cela comprend, notamment, des charges de travail telles que des serveurs HTTP, des serveurs SQL en lecture seule et des serveurs d’annuaire en lecture seule.

En revanche, ce mode de mise à l’échelle ne s’applique pas aux charges de travail qui modifient l’état interne des serveurs (mémoire vive ou stockage local). C’est le cas, par exemple, des serveurs SQL, des serveurs d’annuaire, et des pare-feu. En effet, pour maintenir la cohérence des données dans la grappe, chaque opération d’écriture sur l’un des serveurs doit être propagée à tous les autres à l’aide de protocoles de synchronisation ou de réplication. Par conséquent, chaque serveur de la grappe traite directement ou indirectement la totalité de la charge de travail. L’ajout d’un serveur ne permet donc pas d’augmenter de la capacité de traitement. De plus, si un même objet est modifié sur plusieurs serveurs, il peut y avoir des conflits susceptibles de provoquer une corruption de données. Pour éviter ces conflits et garantir la cohérence des données, il est crucial qu’à tout instant, les requêtes qui modifient l’état du système soient traitées par un seul et unique serveur.

Lorsque la mise à l’échelle horizontale à l’aide d’une grappe ne peut pas être mise en œuvre et que la mise à l’échelle verticale n’est pas une option, il est possible d’avoir recours à des techniques de partitionnement. Dans le domaine des bases de données, l’une de ces techniques est le sharding. L’objectif est de diviser une base de données en plusieurs fragments indépendants (shards) qui peuvent ensuite être distribués sur plusieurs serveurs. Toutefois, contrairement aux grappes de serveurs, ces techniques ne sont généralement pas transparentes pour les clients.

Répartiteur de charge

Pour la mise à l’échelle, une grappe de serveur est généralement réalisée à l’aide d’un répartiteur de charge (load balancer). Ce dernier est un dispositif de routage qui opère au niveau de la couche transport (TCP/UDP) ou de la couche application (p. ex. HTTP) et dont la fonction est de distribuer la charge de travail aux serveurs de la grappe. Il existe différentes stratégies plus ou moins sophistiquées pour répartir la charge, notamment:

  • Round-robin : Chaque serveur reçoit les requêtes à tour de rôle, éventuellement en tenant compte d’une pondération (weighted round-robin) si les serveurs n’ont pas tous la même capacité de traitement.
  • Least connections : Les requêtes sont envoyées vers le serveur qui a le moins de connexions ouvertes en cours.
  • Least response time : Les requêtes sont envoyées vers le serveur qui a la réponse la plus rapide à la dernière requête.
  • IP Hash : La répartition se fait en fonction de l’adresse IP du client. Cette stratégie permet de garantir que les requêtes d’un même client seront toujours envoyées vers le même serveur.

Un répartiteur de charge comprend généralement une fonctionnalité de surveillance (monitoring) de l’état de santé des serveurs. Lorsqu’un des serveurs montre des signes de défaillance, il est retiré de la grappe et n’est plus pris en compte par l’algorithme de répartition jusqu’à ce qu’il soit à nouveau opérationnel.

Il existe un grand nombre de solutions libres et propriétaire pour les répartiteurs de charge. Parmi les solutions libres, on peut mentionner : Keepalived (couche 4) et HAProxy (couche 4 et 7). Selon les besoins, un répartiteur de charge peut prendre la forme d’une machine virtuelle, d’un container, ou d’un équipement réseau. La principale caractéristique à prendre en compte est le débit effectif (throughput) du dispositif, c’est-à-dire le nombre de paquets ou de requêtes que le dispositif est capable de transférer aux serveurs de la grappe par unité de temps.

Protocole de redondance d’adresse et de basculement

Une grappe de haute disponibilité est réalisée à l’aide d’un protocole de redondance d’adresse et de basculement (failover) tel que VRRP (Virtual Router Redundancy Protocol) ou CARP (Common Address Redundancy Protocol) qui permettent à plusieurs hôtes de partager une même adresse IP appelée adresse IP virtuelle. Leur fonction est d’assurer que dans un groupe de serveurs, l’un d’entre eux est actif, et les autres passifs. Le serveur actif reçoit le trafic destiné à l’adresse IP virtuelle. S’il cesse de fonctionner, l’un des serveurs passifs devient le serveur actif (basculement).

Le principe de fonctionnement est toujours le même:

  • Le serveur actif envoie périodiquement une annonce pour indiquer aux autres qu’il est opérationnel.
  • Au démarrage, un serveur est toujours passif et à l’écoute des annonces du serveur actif.
  • Si un serveur passif ne reçoit pas d’annonce durant une période de temps généralement configurable, il lance la procédure d’élection d’un nouveau serveur actif.

Contrairement aux répartiteurs de charge, le nombre de solutions de protocole de redondance d’adresse est plutôt limité. Sous Linux, la solution la plus courante est le protocole VRRP avec Keepalived, et ucarp est une implémentation du protocole CARP.

En pratique, les deux types de grappes sont souvent combinés. Un répartiteur de charge est souvent une grappe à haute disponibilité composée de deux ou trois répartiteurs de charge identiques.

Installation et configuration de Keepalived

La première chose à faire d’installer Keepalived. Pour cela, connectez-vous au premier serveur et installez le paquet keepalived avec le gestionnaire de paquet (apt -y install keepalived), puis recommencer avec le second serveur.

Pour configurer Keepalived, nous avons besoin de l’adresse IP de chacun des deux serveurs et de l’adresse IP virtuelle. Pour cela, utilisez la commande dig pour obtenir les adresses correspondant aux noms d’hôtes des serveurs (svr-m140-$NUM-sql-01.lab.epai-ict.ch et svr-m140-$NUM-sql-02.lab.epai-ict.ch) ainsi que l’adresse virtuelle qui correspond au nom d’hôte svr-m140-$NUM-sql.lab.epai-ict.ch (voir figure 1).

1
2
3
dig svr-m140-$NUM-sql-01.lab.epai-ict.ch +short
dig svr-m140-$NUM-sql-02.lab.epai-ict.ch +short
dig svr-m140-$NUM-sql.lab.epai-ict.ch +short
Fig. 1 – Déterminer les adresses IP du premier et du second serveur et l'adresse IP virtuelle

Après l’installation de Keepalived . Ce fichier est /etc/keepalived/keepalived.conf. Le contenu du fichier pour le premier et second serveur devrait correspondre à la figure 2. Assurez-vous que c’est bien le cas et que les différentes adresses IP correspondent à celles que vous avez obtenues avec la commande dig.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id ###
    priority 20
    advert_int 1
    unicast_src_ip 172.20.###.42
    unicast_peer {
        172.20.###.43
    }
    authentication {
        auth_type PASS
        auth_pass p###
    }
    virtual_ipaddress {
        172.20.###.41
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id ###
    priority 15
    advert_int 1
    unicast_src_ip 172.20.###.43
    unicast_peer {
        172.20.###.42
    }
    authentication {
        auth_type PASS
        auth_pass p###
    }
    virtual_ipaddress {
        172.20.###.41
    }
}
Fig. 2 – Fichier de configuration /etc/keepalived/keepalived.conf du premier et du second serveur

Lorsque vous avez vérifié que la configuration est correcte, démarrez le service keepalived sur les deux serveurs, puis assurez-vous que les deux services sont actifs. Pour cela, lancez les commandes suivantes sur chacun des deux serveurs.

1
2
sudo systemctl restart keepalived
sudo systemctl status keepalived
Fig. 3 – Démarrer et vérifier l'état du service Keepalived

Questions

  1. Sur le premier serveur (svr-m140-$NUM-sql-01.lab.epai-ict.ch), affichez la ou les adresses IP de l’interface ens192 avec la commande ip -4 -br a s ens192. Relevez la ou les adresses. Que constatez-vous?
  2. Sur le second serveur (svr-m140-$NUM-sql-02.lab.epai-ict.ch), lancez la même commande et relevez la ou les adresses de l’interface ens192. Que constatez-vous?
  3. Sur le premier serveur (svr-m140-$NUM-sql-01.lab.epai-ict.ch), arrêtez le service Keealived avec la commande sudo systemctl stop keepalived et affichez le statut du service pour vous assurer qu’il est bien arrêté. Afficher une nouvelle fois la ou les adresses IP de l’interface `ens192. Que constatez-vous?
  4. Lancez la commande ping svr-m140-$NUM-sql.lab.epai-ict.ch. Est-ce qu’un hôte répond? Si oui, quel est cet hôte? Peut-il s’agir du premier serveur (svr-m140-$NUM-sql-01.lab.epai-ict.ch)?
  5. Sur le premier serveur (svr-m140-$NUM-sql-01.lab.epai-ict.ch), redémarrez le service keepalived et afficher encore une fois la ou les adresses IP de l’interface ens192. Que constatez-vous?
  6. Analysez le fichier de configuration et expliquez brièvement tous les champs.

Activer la surveillance du serveur MariaDB

Vous devriez maintenant avoir une grappe de haute disponibilité opérationnelle. Le nom d’hôte de la grappe est svr-m140-$NUM-sql.lab.epai-ict.ch. Le premier est serveur actif et tant qu’il envoie périodiquement une notification pour indiquer qu’il est opérationnel, le second est passif. Si le premier serveur n’envoie plus de notification, le second serveur prend le relai et devient le serveur actif.

Toutefois, la manière dont nous avons configuré Keepalived ne permet pas de déterminer si le serveur MariaDB (le daemon mariadbd) est bien en cours d’exécution et opérationnel. Le serveur est actif tant que le daemon keepalived est actif.

Keepalived permet d’exécuter périodiquement un script qui permet de vérifier la bonne santé du service fournit par la grappe de haute disponibilité, ici le serveur MariaDB. Si le service est opérationnel, le script doit renvoyer le code d’erreur 0. N’importe quel autre code d’erreur indique que le service n’est plus opérationnel. Le code de la figure 4 montre un exemple de script qui vérifie que le processus mariadbd est en cours d’exécution et que le serveur de base de données fonctionne.

Sur le premier serveur (svr-m140-$NUM-sql-01.lab.epai-ict.ch), copiez le code le code de la figure 4 dans un fichier et enregistrez-le sous le nom check-mariadb-health.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /bin/bash

procid=$(/bin/pidof mariadbd)
if [ -z "$procid" ]; then  
    echo "mariadb is not running." >&2
    exit 1
fi

serverStatus=$(/usr/bin/mysql -u health_check -pepai123 -e 'SHOW STATUS \G;')
if [ $? -ne 0 ]; then
  echo "mariadb is not responding" >&2
  exit 1
fi

echo "ok"
exit 0
Fig. 4 – Script de vérification de l'état de santé du serveur MariaDB (/usr/local/bin/check-mariadb-health)

Mofifiez les permissions du script check-mariadb-health et copiez le fichier dans le répertoire /usr/local/bin avec les commandes ci-après.

1
2
3
4
5
sudo groupadd -r keepalived_script
sudo useradd -r -s /sbin/nologin -g keepalived_script -M keepalived_script
sudo cp ./check-mariadb-health /usr/local/bin/check-mariadb-health
sudo chown  keepalived_script:keepalived_script /usr/local/bin/check-mariadb-health
sudo chmod 770 /usr/local/bin/check-mariadb-health
Fig. 5 – Créer l'utilisateur keepalived_script, copier le fichier dans /usr/local/bin et ajuster les permissions du script

Véfifiez que le script fonctionne en l’exécutant avec la commande sudo check-mariadb-health. Si le daemon mariadbd est actif, le script doit écrire ok dans la sortie standard. Essayez d’arrêter le service mariadb et exécutez le script une nouvelle fois. Cette fois, vous devriez voir le message “mariadbd is not running.”.

Si tout fonctionne correctement, modifiez la configuration de Keepalived sur les deux serveurs pour qu’elle ressemble à celle de la figure 6, puis redémarrez le service keepalived.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
global_defs {
    enable_script_security
}

vrrp_script check_mariadb_health {
    script "/usr/local/bin/check-mariadb-health"
    interval 2
    fall 2
    rise 2
}

vrrp_instance VI_1 {

    ...

    track_script {
        check_mariadb_health
    }
}
Fig. 6 – Configuration de la surveillance de l'état de santé du serveur

Si votre configuration est correcte, en arrêtant le service mariadb sur le premier serveur, le second serveur devrait devenir actif.

Questions

  1. Expliquez ce que fait le script de la figure 4.
  2. Expliquez les modifications apportées à la configuration.
  3. Ouvrez une session mysql avec le serveur svr-m140-$NUM-sql.lab.epai-ict.ch depuis votre PC, puis simulez une panne en stoppant le service sur serveur actif (en principe svr-m140-$NUM-sql-01.lab.epai-ict.ch)