La résilience
Le mot est posé, « Résilience ». Dès le titre, certains vont se demander : « Un nouveau framework ? », ou encore « Une nouvelle méthode Agile ? ». Désolé mais non, c’est une notion qui traite d’architecture (technique et applicative). Commençons par une définition :
Définition : La résilience, en informatique, est la capacité d’un système à continuer de fonctionner en cas de panne, d’incidents intentionnels ou non et/ou de sollicitations extrêmes.
Cette définition vous donne déjà une idée de ce que nous allons aborder dans cet article : comment fait-on pour qu’une application soit hautement disponible ? Maintenant que nous savons quel est le but de la résilience, nous allons nous pencher sur les techniques à dispositions pour rendre une application résiliante. En effet, ce procédé s’appuie sur plusieurs notions qui vous sont déjà familières :
◦ Les Tests : Même si l’on assimile les tests à la qualité, et c’est bien de cela qu’il s’agit, ces derniers rendent aussi service à la résilience, car une application de qualité est une application qui ne « crash » pas. Trois types de tests nous intéressent ici (le fonctionnel et le rendu graphique d’une application n’interviennent pas dans la résilience d’une application) :
- Les Tests Unitaires dans un premier temps, bien que l’on ne puisse pas dire qu’ils influent énormément sur la stabilité même d’une application, nous permettent d’assurer que la gestion des erreurs est respectée. En effet, une bonne gestion des erreurs permet de pouvoir remonter les informations au plus vite mais aussi de pouvoir s’assurer que l’on a bien prévu les cas d’erreurs.
Exemple : Imaginons que notre application génère des documents volumineux. Si le cas d’erreur lors de cette génération ne supprime pas les fichiers temporaires, alors il se peut que la taille prise sur le système de fichier augmente et, qu’à terme, nous dépassions l’espace disque alloué sur la machine. - Ensuite, les tests d’intégrations. Ces tests sont comme les tests unitaires, ils n’influent pas directement sur la résilience, cependant ils permettent de valider le fonctionnement de l’application intégré dans son SI.
- Pour finir, les tests de charge, contrairement aux deux précédents, sont directement liés à la résilience, et permettent de définir la charge maximum de l’application, de tester le comportement de l’application en sur-sollicitation, mais aussi de pouvoir tester l’application en mode dégradé. Exemple : Lancement d’un test de charge sur une durée de 4h, montée en charge progressive, dépassement de charge, descente en charge nominale, coupure d’un des serveurs (basculement de base de données par exemple). À la fin de ce test, nous ne devrions pas avoir d’erreurs si notre résilience est bonne (dépassement de charge corrigé par un provisioning à la volée d’un autre serveur, changement de serveur de base de données en reprise à chaud).
◦ La sécurité : La sécurité joue un rôle, quant à elle, important dans la résilience, à elle seule elle répond au besoin d’empêcher les incidents intentionnels.
- La sécurité peut être applicative (intégrée à l’application) ou gérée par des composants de l’infrastructure (Frontal web, Api Gateway, load balancer, proxy ou WAF) : la sécurité a pour mission de contrôler l’accès, de pouvoir appliquer des quotas (ex : rate limiting) et de se protéger des attaques (exemple : déni de service). La sécurité est donc obligatoire lorsque l’on veut une application résiliente. À noter aussi que ces services sont souvent proposés par les hébergeurs.
- La supervision : contrairement aux deux points précédents, nous ne sommes plus dans le domaine du préventif mais dans celui du correctif (temps réel ou post erreur). La supervision est donc un point important dans la résilience, c’est elle qui surveille l’état de santé de l’application mais aussi surveille les ressources du/des host(s). Trois points sont à noter pour que cette dernière réalise son travail au mieux :
- Remontées de métriques, aussi bien système (Ram, CPU, Réseau, Espace disque) qu’applicatif (temps de réponse, nombre de connexions à la base, code retour).
- Une bonne pratique appréciable aussi est entry point de type heathcheck. Il permet de donner l’état de santé de l’application à un instant T (connexion à la base opérationnelle, version de l’application, nombre de requêtes, nombre de sessions actives, etc).
- La supervision a aussi un rôle important : effectuer des actions correctives. En effet nous pouvons demander à la supervision, en plus d’alerter, d’effectuer des actions en cas de remontées de problèmes. Exemple : augmenter l’espace disque au besoin, provisionner une nouvelle machine, redémarrer un service ou encore modifier une configuration d’un frontal web afin d’afficher un message d’indisponibilité.
◦ L’architecture : nous arrivons dans le vif du sujet, ne pas oublier que l’un des services rendus par la résilience est la haute disponibilité de l’application. Pour ce faire, nous allons nous appuyer sur :
- Une infrastructure du SI adaptée : cela peut aller d’un simple service d’hébergement cloud à un hébergement multi datacenter. Nous verrons un peu plus tard, dans les schémas d’exemple, les différentes possibilités.
- Un stockage de données partageable entre différentes machines. Ce point, très important, est à adapter en fonction des besoins, voici quelques moyens à dispositions :
- NAS / SAN (ou serveur de fichiers): centralisé, non local aux machines, peut souffrir de latences réseau (avec une technologie RAID 1/0/5, nous pouvons assurer la sauvegarde des données, une vitesse d’écriture/lecture accrue).
- Système de fichiers distribué en parallèle, comme GlusterFS, qui permet d’utiliser un système de fichiers local mais synchronisé entre les différentes machines.
- Un stockage de données (Base de données relationnelle ou non, NoSql, etc…) en mode Maître/Esclave. Exemple : Redis / Mysql / PostgreSql / Oracle.
- Un Gestionnaire de données en typologie étoile, typiquement Apache Cassandra, permettant un partage de données multi-datacenter et n’ayant que des nœuds maîtres.
- La redondance des données et des services, multiplier les instances, qu’elles soient en mode active/passive ou load-balancé (round robin ou sticky session).
- La scalabilité horizontale, qui permet de provisionner des services à la volée (Duplication de VM, Orchestrateur Docker) et donc de répondre à des pics de charge. Il est à noter aussi que ce procédé est économiquement intéressant, car cela évite de surdimensionner des serveurs pour qu’ils répondent à des pics de charge exceptionnels.
- Un développement des applications adapté à cette architecture technique. Nous prendrons pour exemple une application utilisant du cache et une session utilisateur, dans le cas d’une architecture distribuée. Il est donc nécessaire de prévoir un partage de session et de cache (FS, Base de données, Multicast, etc…).
Il est intéressant de noter que Docker peut simplifier la mise en place d’une application résiliente. En effet, les fonctionnalités comme le redémarrage automatique, le healthcheck ou encore traefik (load-balancer) ainsi que la scalabilité offerte par les orchestrateurs sont des points qui ne seront pas à traiter par les exploitants.
Bien sûr, tout cela a un coût, et plus nous souhaitons être hautement disponible plus le coût est élevé. Il est donc primordial de bien analyser ses besoins avant de se lancer dans l’aventure. Cependant, nous sommes forcés de constater aujourd’hui que bien des applications ne sont pas résilientes, ce sujet sera donc à suivre dans les années à venir.
Exemples architectures
Résilience faible
L’exemple ci-contre présente une application dont la résilience n’est pas forte mais qui permet d’assurer un service en cas de panne (application dont la haute disponibilité n’est pas un point d’attention).
Un Frontal web s’occupe de load-balancer en mode actif/passif sur deux machine ayant l’application. Le partage des données se fait sur un NAS monté sur les deux machines. Si la machine active ne répond plus, le load balancer redirigera les flux sur l’autre machine.
AN : Ce processus permet aussi de pouvoir effectuer des mises en production sans perte de continuité de service
Résilience intermédiaire
Voici un exemple d’une application qui se veut déjà bien résiliente. L’application est livrée sous forme de containers Docker, un analyseur de charge permet de lancer des réplicats supplémentaires en fonction de la charge, 4 noeuds swarm sur différentes machines permettent de répartir les ressources et le système de fichiers est distribué en parallèle. Le tout chez un hébergeur qui assure les services de sécurité.
Résilience forte
Sur l’architecture ci-après, nous pouvons voir que nous avons adapté le fonctionnement de l’exemple précédent en répartissant les charges sur plusieurs data-center, mais aussi un gestionnaire de données en typologie étoile qui permet à l’application d’accéder à la donnée la plus “proche” du datacenter.
Vous l’aurez compris, la résilience est un sujet vaste, qui doit s’adapter à chaque besoin et à chaque portefeuille. Dans un projet, la résilience ne touche pas qu’à l’architecture technique mais aussi à l’architecture applicative. De nombreux tests sont à mettre en place afin de valider son bon fonctionnement, mais pour ça, nous connaissons tous dans notre entourage une personne qui serait heureuse d’entendre : “Voilà, tu as 2h pour essayer de faire tomber mon service”.