Le Blog Amazon Web Services
AWS et la compartimentation (architecture cellulaire)
Pratiquement tous les conducteurs expérimentés ont déjà eu un pneu crevé. C’est vraiment embêtant : vous vous arrêtez sur le côté de la route, videz le coffre pour sortir la roue de secours, levez la voiture avec un cric et remplacez la route crevée avant de vous rendre dans un garage de réparation à proximité. Pour une voiture, cela peut être gérable. Nous pouvons tolérer ces désagréments occasionnels, et en tant que conducteurs, nous ne sommes jamais très loin d’un endroit sûr pour nous arrêter ou d’un garage amical.
En utilisant le vocabulaire de disponibilité et de la résilience, une roue de secours est une sorte de solution de secours, un composant ou un système qui attend de manière passive d’être déployé lorsque nécessaire. Ce concept est également courant dans les systèmes informatiques. Par exemple, de nombreuses bases de données reposent sur une bascule en cas de panne, et certaines d’entre elles nécessitent même une intervention manuelle, où un être humain exécute un script comme on pourrait monter un cric de voiture (bien que nous recommandions d’automatiser et adapter la stratégie de reprise en fonction du contexte).
Mais lorsque les enjeux sont plus importants, il est préférable d’adopter une autre conception. Prenons par exemple les systèmes d’un avion de ligne moderne qui globalement affichent un excellent bilan de sécurité. Un avion ne peut pas se garer sur le côté de la route, et en cas de problème, un avion de ligne peut devoir voler pendant plusieurs heures avant d’être à portée d’une piste d’atterrissage. Pour les avions de ligne, il est courant que les systèmes critiques utilisent une redondance active. Par exemple, un avion à deux moteurs peut voler avec un seul moteur en marche, de sorte que si l’un d’eux tombe en panne, l’autre peut facilement maintenir l’avion en l’air.
Ce genre de modèle est également courant dans les grands systèmes web. Par exemple, de nombreux serveurs Amazon EC2 gèrent amazon.com, lorsqu’un serveur tombe en panne de manière occasionnelle, il y a une capacité tampon répartie sur les autres serveurs qui garantit que les clients ne s’en rendent même pas compte.Les moteurs d’avion ne tombent pas en panne d’eux-mêmes. Chacun des dizaines de composants – les contrôleurs de moteur numériques, les conduites et les pompes de carburant, les engrenages et les arbres, et ainsi de suite – peut provoquer l’arrêt du moteur. Pour chacun de ces composants, les concepteurs d’aéronefs pourraient essayer d’inclure une certaine redondance au niveau des composants (et certains le font, comme l’avionique), mais le nombre est si conséquent qu’il est plus facile de repenser la conception en termes d’isolation de pannes ou de compartimentation : tant que chaque moteur dépend d’instances séparées de chaque composant, aucun composant ne peut mettre hors service les deux moteurs. Une conduite de carburant peut se rompre, mais elle ne peut arrêter qu’un seul moteur, et l’avion a déjà été conçu pour fonctionner avec un moteur en panne.
Ce type de compartimentation est particulièrement utile pour les systèmes informatiques complexes. Un grand site web ou un service web peut dépendre de dizaines, voire de centaines de sous-services. Seuls un certain nombre d’entre eux peuvent inclure une redondance active robuste. En alignant les instances de sous-services de manière à ce que les interdépendances ne traversent jamais les compartiments ou les cellules, nous pouvons nous assurer qu’un problème peut être contenu dans la cellule où il a commencé. Cela signifie également que nous pouvons essayer de résoudre les problèmes en mettant en quarantaine des cellules entières, sans avoir besoin de trouver la cause première du problème à l’intérieur de la cellule.
AWS et la compartimentation
Amazon Web Services propose des fonctionnalités et des offres qui permettent une compartimentation en cellules efficace. Tout d’abord, de nombreux services d’Amazon Web Services, tels que Amazon S3 et Amazon RDS, sont eux-mêmes compartimentés et isolés en interne et utilisent des concepts de redondance active afin de masquer les défaillances lorsqu’elles se produisent.
Nous proposons également des services web et des ressources de différentes tailles, ainsi que des fonctionnalités d’automatisation telles que l’auto-scaling, l’Infrastructure-As-Code AWS CloudFormation ou CDK (Cloud Development Kit), qui facilitent la gestion d’un plus grand nombre d’instances.
Il existe une distinction subtile mais importante entre l’exécution d’un petit nombre de grandes instances et l’exécution d’un grand nombre de petites instances. Quatre instances t4g.xlarge
coûtent autant que deux instances t4g.2xlarge
et fournissent la même quantité de CPU et de stockage ; mais pour les configurations à haute disponibilité, l’utilisation de quatre instances ne nécessite qu’une capacité tampon de basculement de 33 % et tout problème au niveau de l’hôte peut avoir un impact sur un quart de votre charge, tandis que l’utilisation de deux instances signifie une capacité tampon de 100 % et tout problème peut avoir un impact sur la moitié de votre charge.
Troisièmement, Amazon Web Services propose des cellules prédéfinies : au minimum trois zones de disponibilité par région. Ces zones de disponibilité sont compartimentées en profondeur jusqu’au niveau des centres de données, du réseau et de l’alimentation électrique.
Supposons que nous créions un site web ou un service web qui utilise quatre zones de disponibilité. Cela signifie que nous avons besoin d’une capacité tampon de basculement de 25 % par zone (ce qui se compare avantageusement à une capacité tampon de basculement de 100 % dans un modèle standard à deux centres de données). Notre service se compose d’une interface frontale, de deux services backend dépendants (« Foo » et « Bar ») et d’un magasin de données (pour cet exemple, nous utiliserons S3).
En limitant les appels aux sous-services pour rester « au sein » de la zone de disponibilité, il est plus facile d’isoler les erreurs. Si le service backend « Bar » échoue (par exemple, un plantage logiciel) dans la zone de disponibilité us-east-1b, cela impacte 1/4 de notre capacité globale.
Au départ, cela peut ne pas sembler beaucoup mieux que si nous avions réparti les appels vers le service Bar depuis toutes les zones sur toutes les instances du service Bar ; après tout, le taux de défaillance serait également d’un cinquième. Mais la différence est profonde.
Tout d’abord, l’expérience a montré que les petits problèmes peuvent souvent être amplifiés dans les systèmes complexes. Par exemple, si le service « Foo » met plus de temps à traiter un appel échoué vers le service « Bar », alors le problème initial avec le service « Bar » commence à avoir un impact sur le comportement de « Foo » et, par conséquent, sur les interfaces frontales.
Deuxièmement, en disposant d’un mécanisme polyvalent simple pour basculer en dehors de la zone de disponibilité impactée, le problème peut être neutralisé de manière fiable, simple et rapide, tout comme un avion peut être conçu pour voler avec un seul moteur et de nombreux types de défaillance gérés avec une seule procédure – si le moteur ne fonctionne pas correctement et qu’une liste de vérifications de quelques actions ne parvient pas à le rétablir, il suffit de l’arrêter et d’atterrir à l’aéroport suivant.
Route 53 Infima
Notre mécanisme suggéré pour gérer ce type de défaillance est le basculement DNS d’Amazon Route 53. Étant donné que le DNS est le service qui transforme les noms de services/sites web en une liste d’adresses IP spécifiques des interfaces frontales auxquelles se connecter, il se situe au début de chaque requête et constitue une couche idéale pour neutraliser les problèmes.
Avec les vérifications d’état de santé de Route 53 et le basculement DNS, chaque interface frontale est constamment vérifiée au niveau de l’état de santé et automatiquement supprimée du DNS en cas de problème. Les URL de vérification d’état de santé de Route 53 sont entièrement personnalisables et peuvent pointer vers un script qui vérifie chaque dépendance dans la zone de disponibilité (« Est-ce que Foo fonctionne, est-ce que Bar fonctionne, S3 est-il accessible, etc. »).
Cela nous amène à Route 53 Infima comme exemple. Infima est une bibliothèque conçue pour modéliser la compartimentation de manière systématique et aider à représenter ce type de configurations dans le DNS. Avec Infima, vous attribuez des enpoints à des compartiments ou cellules spécifiques tels que la zone de disponibilité. Pour des configurations avancées, vous pouvez également ajouter des dimensions supplémentaires de compartimentation ; par exemple, vous pouvez souhaiter exécuter deux implémentations logicielles différentes du même service (peut-être pour des déploiements blue/green ou une redondance au niveau de l’application) dans chaque zone de disponibilité.
Une fois que la bibliothèque Infima a appris la disposition des endpoints dans les cellules, des défaillances peuvent être simulées dans le logiciel par un service tel que AWS Fault Injection Simulator et toute lacune de capacité peut être identifiée. Mais la véritable puissance d’Infima réside dans l’expression de ces configurations dans le DNS. Notre exemple de service comportait 4 endpoints répartis dans 4 zones de disponibilité. Une option pour exprimer cela dans le DNS consiste à renvoyer chaque point d’extrémité une fois sur quatre. Chaque réponse pourrait également dépendre d’une vérification d’état de santé, et en cas d’échec de la vérification d’état de santé, elle pourrait être supprimée du DNS. Infima prend en charge cette configuration.
Cependant, il existe une meilleure option. Le DNS (et naturellement Route 53) permet à plusieurs points d’extrémité d’être représentés dans une seule réponse, par exemple :
Lorsque les clients (tels que les navigateurs ou les clients de services web) reçoivent ces réponses, ils essaient généralement plusieurs points d’extrémité jusqu’à ce qu’ils trouvent celui qui se connecte avec succès. Ainsi, en incluant tous les points d’extrémité, nous gagnons une certaine tolérance aux pannes. Cependant, lorsqu’un point d’extrémité échoue, comme nous l’avons déjà vu, le problème peut se propager et les clients peuvent subir des temporisations de nouvelle tentative et des retards. Il est donc souhaitable de supprimer les adresses IP des réponses DNS en temps opportun.
Infima peut utiliser la liste des cellules, des endpoints et de leurs vérifications d’état de santé pour construire un arbre de décision précalculé des réponses DNS qui contient des réponses préconfigurées prêtes et en attente en cas de défaillances potentielles : un seul nœud qui échoue, une cellule entière qui échoue, des combinaisons de chaque cas, et ainsi de suite. Cet arbre de décision est ensuite stocké en tant que configuration Route 53 et peut gérer automatiquement toutes les défaillances. Ainsi, si le point d’extrémité 192.0.2.3 venait à échouer, alors :
sera retourné. En ayant ces arbres de décision pré-configurés toujours prêts et en attente, Route 53 est en mesure de réagir rapidement aux défaillances des points d’extrémité, ce qui signifie que nous sommes également prêts à gérer les défaillances de tout sous-service desservant ce point d’extrémité grâce à la compartimentation.
La compartimentation que nous avons vue jusqu’à présent est particulièrement utile pour certains types d’erreurs : les problèmes au niveau de l’hôte, les pannes occasionnelles, les blocages d’application. Cependant, si le problème provient des demandes au niveau de l’interface frontale elles-mêmes, par exemple une attaque de déni de service ou une demande « poison » qui déclenche un bogue catastrophique, il peut rapidement impacter l’ensemble de vos cellules.
Contenu bonus : Contourner les caches DNS
Nous avons mentionné l’importance de supprimer rapidement les endpoints défaillants de DNS, même lorsqu’il y a plusieurs points d’extrémité dans une réponse. Un problème auquel nous répondons dans ce domaine est le cache DNS au niveau de l’application qui ne fonctionne pas correctement. Certaines plateformes, y compris de nombreuses versions de Java, ne respectent pas les durées de vie du cache DNS (la valeur de temps de vie ou TTL du DNS), et une fois qu’une réponse DNS a été résolue, elle est utilisée indéfiniment.
Une façon d’atténuer ce problème est d’utiliser une technique appelée « busting » ou contournement de cache. Route 53 prend en charge les enregistrements génériques (wildcard records) (ainsi que les alias génériques, les CNAME et plus encore). Au lieu d’utiliser un nom de service tel que « api.example.com », il est possible d’utiliser un nom générique tel que « *.api.example.com », qui correspondra aux requêtes pour tout nom se terminant par « .api.example.com ».
Une application peut alors être développée de manière à résoudre un nom partiellement aléatoire, par exemple « sdsHdsk3.api.example.com ». Ce nom, étant donné qu’il se termine par api.example.com, recevra toujours la bonne réponse, mais étant donné qu’il s’agit d’un nom aléatoire unique à chaque fois, il permettra de contourner tout cache DNS défectueux au niveau de la plateforme ou du système d’exploitation.
Article original rédigé en anglais par Colm MacCarthaigh, Senior Principal Engineer chez AWS, et traduit par Djamel Bourokba, Sr Global Solutions Architect au sein des équipes AWS Automotive and Manufacturing.