Conception d’applications de charges de travail stratégiques sur Azure

Lorsque vous concevez une application, les exigences d’application fonctionnelles et non fonctionnelles sont essentielles. Cette zone de conception décrit les modèles d’architecture et les stratégies de mise à l’échelle qui peuvent vous aider à rendre votre application résiliente aux défaillances.

Important

Cet article fait partie de la série de charges de travail stratégiques Azure Well-Architected Framework . Si vous n’êtes pas familiarisé avec cette série, nous vous recommandons de commencer par Qu’est-ce qu’une charge de travail stratégique ?.

Architecture d’unité d’échelle

Tous les aspects fonctionnels d’une solution doivent être capables de mettre à l’échelle pour répondre aux changements de la demande. Nous vous recommandons d’utiliser une architecture d’unité de mise à l’échelle pour optimiser la scalabilité de bout en bout grâce à la compartimentation, ainsi que pour standardiser le processus d’ajout et de suppression de capacité. Une unité de mise à l’échelle est une unité logique ou une fonction qui peut être mise à l’échelle indépendamment. Une unité peut être composée de composants de code, de plateformes d’hébergement d’applications, de tampons de déploiement qui couvrent les composants associés et même d’abonnements pour prendre en charge les exigences multilocataires.

Nous recommandons cette approche, car elle répond aux limites de mise à l’échelle des ressources individuelles et de l’application entière. Il facilite les scénarios de déploiement et de mise à jour complexes, car une unité de mise à l’échelle peut être déployée en tant qu’unité. En outre, vous pouvez tester et valider des versions spécifiques de composants dans une unité avant d’y diriger le trafic utilisateur.

Supposons que votre application stratégique soit un catalogue de produits en ligne. Il dispose d’un flux utilisateur pour le traitement des commentaires et des évaluations des produits. Le flux utilise des API pour récupérer et publier des commentaires et des évaluations, ainsi que des composants de prise en charge tels qu’un point de terminaison OAuth, un magasin de données et des files d’attente de messages. Les points de terminaison d’API sans état représentent des unités fonctionnelles granulaires qui doivent s’adapter aux modifications à la demande. La plateforme d’application sous-jacente doit également être en mesure de mettre à l’échelle en conséquence. Pour éviter les goulots d’étranglement des performances, les composants et dépendances en aval doivent également être mis à l’échelle à un degré approprié. Ils peuvent soit effectuer une mise à l’échelle indépendamment, en tant qu’unités d’échelle distinctes, soit ensemble, dans le cadre d’une seule unité logique.

Exemples d’unités de mise à l’échelle

L’image suivante montre les étendues possibles pour les unités d’échelle. Les étendues vont des pods de microservice aux nœuds de cluster et aux empreintes de déploiement régional.

Diagramme montrant plusieurs étendues pour les unités de mise à l’échelle.

Considérations en matière de conception

  • Portée. L’étendue d’une unité d’échelle, la relation entre les unités d’échelle et leurs composants doivent être définies en fonction d’un modèle de capacité. Prenez en compte les exigences non fonctionnelles en matière de performances.

  • Limites de mise à l’échelle. Les limites et quotas de mise à l’échelle des abonnements Azure peuvent avoir une incidence sur la conception des applications, les choix technologiques et la définition des unités de mise à l’échelle. Les unités de mise à l’échelle peuvent vous aider à contourner les limites de mise à l’échelle d’un service. Par exemple, si un cluster AKS dans une unité ne peut avoir que 1 000 nœuds, vous pouvez utiliser deux unités pour augmenter cette limite à 2 000 nœuds.

  • Charge attendue. Utilisez le nombre de demandes pour chaque flux d’utilisateur, le taux de pic de demande attendu (demandes par seconde) et les modèles de trafic quotidien/hebdomadaire/saisonnier pour informer les besoins de mise à l’échelle de base. Tenez également compte des modèles de croissance attendus pour le trafic et le volume de données.

  • Performances dégradées acceptables. Déterminez si un service dégradé avec des temps de réponse élevés est acceptable sous charge. Lorsque vous modélisez la capacité requise, les performances requises de la solution sous charge sont un facteur critique.

  • Exigences non fonctionnelles. Les scénarios techniques et métier ont des considérations distinctes en matière de résilience, de disponibilité, de latence, de capacité et d’observabilité. Analysez ces exigences dans le contexte des flux d’utilisateurs clés de bout en bout. Vous disposez d’une flexibilité relative dans la conception, la prise de décision et les choix technologiques au niveau du flux utilisateur.

Recommandations de conception

  • Définissez l’étendue d’une unité d’échelle et les limites qui déclencheront l’unité à mettre à l’échelle.

  • Assurez-vous que tous les composants d’application peuvent être mis à l’échelle indépendamment ou dans le cadre d’une unité de mise à l’échelle qui inclut d’autres composants associés.

  • Définissez la relation entre les unités d’échelle, en fonction d’un modèle de capacité et des exigences non fonctionnelles.

  • Définissez un tampon de déploiement régional pour unifier l’approvisionnement, la gestion et le fonctionnement des ressources d’application régionales en une unité d’échelle hétérogène mais interdépendante. À mesure que la charge augmente, des empreintes supplémentaires peuvent être déployées, dans la même région Azure ou dans différentes, pour mettre à l’échelle horizontalement la solution.

  • Utilisez un abonnement Azure comme unité de mise à l’échelle afin que les limites de mise à l’échelle au sein d’un seul abonnement ne limitent pas la scalabilité. Cette approche s’applique aux scénarios d’application à grande échelle qui ont un volume de trafic important.

  • Modéliser la capacité requise autour des modèles de trafic identifiés pour s’assurer qu’une capacité suffisante est provisionnée aux heures de pointe pour empêcher la dégradation du service. Vous pouvez également optimiser la capacité pendant les heures creuses.

  • Mesurez le temps nécessaire pour effectuer des opérations de scale-out et de scale-in pour vous assurer que les variations naturelles du trafic ne créent pas un niveau inacceptable de dégradation du service. Suivez les durées des opérations de mise à l’échelle en tant que métrique opérationnelle.

Notes

Lorsque vous effectuez un déploiement dans une zone d’atterrissage Azure, assurez-vous que l’abonnement à la zone d’atterrissage est dédié à l’application afin de fournir une limite de gestion claire et d’éviter l’antimodèle voisin bruyant.

Diffusion mondiale

Il est impossible d’éviter une défaillance dans un environnement hautement distribué. Cette section fournit des stratégies pour atténuer de nombreux scénarios d’erreur. L’application doit être en mesure de résister aux défaillances régionales et zonales. Il doit être déployé dans un modèle actif/actif afin que la charge soit répartie entre toutes les régions.

Regardez cette vidéo pour obtenir une vue d’ensemble de la façon de planifier les défaillances dans les applications stratégiques et d’optimiser la résilience :

Considérations en matière de conception

  • Redondance. Votre application doit être déployée dans plusieurs régions. En outre, au sein d’une région, nous vous recommandons vivement d’utiliser des zones de disponibilité pour autoriser la tolérance de panne au niveau du centre de données. Les zones de disponibilité ont un périmètre de latence inférieur à 2 millisecondes entre les zones de disponibilité. Pour les charges de travail qui sont « bavardes » entre les zones, cette latence peut entraîner une pénalité de performances et entraîner des frais de bande passante pour le transfert de données interzones.

  • Modèle actif/actif. Une stratégie de déploiement actif/actif est recommandée, car elle optimise la disponibilité et fournit un contrat de niveau de service (SLA) composite plus élevé. Toutefois, cela peut présenter des défis liés à la synchronisation et à la cohérence des données dans de nombreux scénarios d’application. Relevez les défis au niveau de la plateforme de données tout en tenant compte des compromis liés à l’augmentation des coûts et des efforts d’ingénierie.

    Un déploiement actif/actif sur plusieurs fournisseurs de cloud est un moyen d’atténuer potentiellement la dépendance à l’égard des ressources globales au sein d’un seul fournisseur de cloud. Toutefois, une stratégie de déploiement multicloud actif/actif introduit une grande complexité autour de CI/CD. En outre, étant donné les différences de spécifications et de fonctionnalités de ressources entre les fournisseurs de cloud, vous avez besoin d’empreintes de déploiement spécialisées pour chaque cloud.

  • Distribution géographique. La charge de travail peut avoir des exigences de conformité pour la résidence des données géographiques, la protection des données et la rétention des données. Déterminez s’il existe des régions spécifiques où les données doivent résider ou où les ressources doivent être déployées.

  • Origine de la demande. La proximité géographique et la densité des utilisateurs ou des systèmes dépendants doivent guider les décisions de conception concernant la distribution globale.

  • Connectivité. La façon dont les utilisateurs ou les systèmes externes accèdent à la charge de travail influence votre conception. Déterminez si l’application est disponible sur l’Internet public ou les réseaux privés qui utilisent des circuits VPN ou Azure ExpressRoute.

Pour connaître les recommandations de conception et les choix de configuration au niveau de la plateforme, consultez Plateforme d’application : distribution globale.

Architecture pilotée par les événements faiblement couplée

Le couplage permet la communication entre services via des interfaces bien définies. Un couplage libre permet à un composant d’application de fonctionner indépendamment. Un style d’architecture de microservices est cohérent avec les exigences stratégiques. Il facilite la haute disponibilité en empêchant les défaillances en cascade.

Pour un couplage souple, nous vous recommandons vivement d’incorporer une conception pilotée par les événements. Le traitement asynchrone des messages par le biais d’un intermédiaire peut générer une résilience.

Diagramme illustrant la communication asynchrone pilotée par les événements.

Dans certains scénarios, les applications peuvent combiner un couplage lâche et serré, en fonction des objectifs de l’entreprise.

Considérations en matière de conception

  • Dépendances d’exécution. Les services faiblement couplés ne doivent pas être contraints d’utiliser la même plateforme de calcul, le même langage de programmation, le même runtime ou le même système d’exploitation.

  • Mise à l’échelle. Les services doivent pouvoir être mis à l’échelle indépendamment. Optimisez l’utilisation des ressources d’infrastructure et de plateforme.

  • Tolérance de panne. Les échecs doivent être gérés séparément et ne doivent pas affecter les transactions clientes.

  • Intégrité transactionnelle. Tenez compte de l’effet de la création et de la persistance des données qui se produisent dans des services distincts.

  • Traçage distribué. Le suivi de bout en bout peut nécessiter une orchestration complexe.

Recommandations de conception

  • Alignez les limites des microservices avec les flux d’utilisateurs critiques.

  • Utilisez la communication asynchrone pilotée par les événements lorsque cela est possible pour prendre en charge une mise à l’échelle durable et des performances optimales.

  • Utilisez des modèles tels que la boîte d’envoi et la session transactionnelle pour garantir la cohérence afin que chaque message soit traité correctement.

Exemple : approche pilotée par les événements

L’implémentation de référence Mission-Critical Online utilise des microservices pour traiter une transaction métier unique. Il applique les opérations d’écriture de façon asynchrone avec un répartiteur de messages et un worker. Les opérations de lecture sont synchrones, le résultat étant directement retourné à l’appelant.

Diagramme montrant la communication basée sur les événements.

Modèles de résilience et gestion des erreurs dans le code d’application

Une application stratégique doit être conçue pour être résiliente afin de résoudre autant de scénarios de défaillance que possible. Cette résilience optimise la disponibilité et la fiabilité du service. L’application doit avoir des fonctionnalités de réparation automatique, que vous pouvez implémenter à l’aide de modèles de conception tels que Nouvelles tentatives avec backoff et disjoncteur.

Pour les défaillances non temporaires que vous ne pouvez pas atténuer entièrement dans la logique d’application, le modèle d’intégrité et les wrappers opérationnels doivent prendre des mesures correctives. Le code d’application doit incorporer une instrumentation et une journalisation appropriées pour informer le modèle d’intégrité et faciliter la résolution des problèmes ou l’analyse de la cause racine si nécessaire. Vous devez implémenter le suivi distribué pour fournir à l’appelant un message d’erreur complet qui inclut un ID de corrélation en cas de défaillance.

Des outils comme Application Insights peuvent vous aider à interroger, mettre en corrélation et visualiser les traces d’application.

Considérations en matière de conception

  • Configurations appropriées. Il n’est pas rare que des problèmes temporaires provoquent des défaillances en cascade. Par exemple, une nouvelle tentative sans interruption appropriée aggrave le problème lorsqu’un service est limité. Vous pouvez espacer les retards de nouvelle tentative de manière linéaire ou les augmenter de façon exponentielle pour reculer en cas de retard croissant.

  • Points de terminaison d’intégrité. Vous pouvez exposer des vérifications fonctionnelles dans le code d’application à l’aide de points de terminaison d’intégrité que les solutions externes peuvent interroger pour récupérer les status d’intégrité des composants de l’application.

Recommandations de conception

Voici quelques modèles courants d’ingénierie logicielle pour les applications résilientes :

Modèle Résumé
Nivellement de la charge basé sur une file d’attente Introduit une mémoire tampon entre les consommateurs et les ressources demandées pour garantir des niveaux de charge cohérents. Lorsque les demandes des consommateurs sont mises en file d’attente, un processus de travail les gère par rapport à la ressource demandée à un rythme défini par le worker et par la capacité de la ressource demandée à traiter les demandes. Si les consommateurs attendent des réponses à leurs demandes, vous devez implémenter un mécanisme de réponse distinct. Appliquez un ordre de priorité afin que les activités les plus importantes soient effectuées en premier.
Disjoncteur Fournit une stabilité en attendant une récupération ou en rejetant rapidement des demandes plutôt qu’en se bloquant en attendant qu’un service ou une ressource distant ne soit pas disponible. Ce modèle gère également les erreurs qui peuvent prendre un temps variable de récupération à partir d’une connexion à un service ou à une ressource distant.
Cloisonnement Tente de partitionner des instances de service en groupes en fonction des exigences de charge et de disponibilité, en isolant les échecs pour maintenir les fonctionnalités du service.
Saga Gère la cohérence des données entre les microservices qui ont des magasins de données indépendants en veillant à ce que les services se mettent à jour les uns les autres via des canaux d’événements ou de messages définis. Chaque service effectue des transactions locales pour mettre à jour son propre état et publie un événement pour déclencher la prochaine transaction locale dans la saga. Si une mise à jour de service échoue, la saga exécute des transactions de compensation pour contrer les étapes de mise à jour de service précédentes. Les étapes de mise à jour de service individuelles peuvent elles-mêmes implémenter des modèles de résilience, comme une nouvelle tentative.
Surveillance de point de terminaison d’intégrité Implémente des vérifications fonctionnelles dans une application auxquelles les outils externes peuvent accéder via des points de terminaison exposés à intervalles réguliers. Vous pouvez interpréter les réponses des points de terminaison à l’aide de métriques opérationnelles clés pour informer l’intégrité de l’application et déclencher des réponses opérationnelles, telles que le déclenchement d’une alerte ou l’exécution d’un déploiement de restauration de compensation.
Nouvelle tentative Gère les défaillances temporaires de manière élégante et transparente.
- Annuler si l’erreur est peu susceptible d’être temporaire et qu’il est peu probable qu’elle réussisse si l’opération est à nouveau tentée.
- Réessayez si l’erreur est inhabituelle ou rare et si l’opération est susceptible de réussir si elle est tentée de nouveau immédiatement.
- Réessayez après un délai si l’erreur est due à une condition qui peut nécessiter un court laps de temps de récupération, comme la connectivité réseau ou les défaillances de charge élevée. Appliquez une stratégie d’interruption appropriée à mesure que les retards de nouvelle tentative augmentent.
Limitation Contrôle la consommation des ressources utilisées par les composants d’application, en les protégeant contre les surcharges. Lorsqu’une ressource atteint un seuil de charge, elle reporte les opérations de priorité inférieure et dégrade les fonctionnalités non essentielles afin que les fonctionnalités essentielles puissent continuer jusqu’à ce que des ressources suffisantes soient disponibles pour revenir à un fonctionnement normal.

Voici quelques recommandations supplémentaires :

  • Utilisez les kits SDK fournis par le fournisseur, comme les kits SDK Azure, pour vous connecter à des services dépendants. Utilisez des fonctionnalités de résilience intégrées au lieu d’implémenter des fonctionnalités personnalisées.

  • Appliquez une stratégie d’interruption appropriée lors de la nouvelle tentative d’appel de dépendance ayant échoué pour éviter un scénario DDoS auto-infligé.

  • Définissez des critères d’ingénierie communs pour toutes les équipes de microservices d’application afin d’améliorer la cohérence et la vitesse d’utilisation des modèles de résilience au niveau de l’application.

  • Implémentez des modèles de résilience à l’aide de packages standardisés éprouvés, comme Polly pour C# ou Sentinel pour Java.

  • Utilisez des ID de corrélation pour tous les événements de trace et les messages de journal pour les lier à une demande donnée. Retournez les ID de corrélation à l’appelant pour tous les appels, et pas seulement pour les demandes en échec.

  • Utilisez la journalisation structurée pour tous les messages de journal. Sélectionnez un récepteur de données opérationnelles unifié pour les traces, les métriques et les journaux d’application afin de permettre aux opérateurs de déboguer facilement les problèmes. Pour plus d’informations, consultez Collecter, agréger et stocker des données de supervision pour les applications cloud.

  • Vérifiez que les données opérationnelles sont utilisées avec les exigences métier pour informer un modèle d’intégrité d’application.

Sélection du langage de programmation

Il est important de sélectionner les langages de programmation et les infrastructures appropriés. Ces décisions sont souvent pilotées par les ensembles de compétences ou les technologies standardisées dans le organization. Toutefois, il est essentiel d’évaluer les performances, la résilience et les fonctionnalités globales de différents langages et infrastructures.

Considérations en matière de conception

  • Fonctionnalités du kit de développement. Il existe des différences dans les fonctionnalités offertes par les kits SDK de service Azure dans différents langages. Ces différences peuvent influencer votre choix d’un service Azure ou d’un langage de programmation. Par exemple, si Azure Cosmos DB est une option réalisable, Go n’est peut-être pas un langage de développement approprié, car il n’existe aucun KIT de développement logiciel (SDK) interne.

  • Mises à jour des fonctionnalités. Réfléchissez à la fréquence à laquelle le SDK est mis à jour avec de nouvelles fonctionnalités pour la langue sélectionnée. Les kits SDK couramment utilisés, comme les bibliothèques .NET et Java, sont fréquemment mis à jour. D’autres kits SDK ou sdk pour d’autres langues peuvent être mis à jour moins fréquemment.

  • Plusieurs langages de programmation ou frameworks. Vous pouvez utiliser plusieurs technologies pour prendre en charge différentes charges de travail composites. Toutefois, vous devez éviter l’étalement, car il présente une complexité de gestion et des défis opérationnels.

  • Option de calcul. Les logiciels hérités ou propriétaires peuvent ne pas s’exécuter dans les services PaaS. En outre, vous ne pourrez peut-être pas inclure des logiciels hérités ou propriétaires dans des conteneurs.

Recommandations de conception

  • Évaluez tous les kits SDK Azure pertinents pour les fonctionnalités dont vous avez besoin et les langages de programmation que vous avez choisis. Vérifiez l’alignement avec les exigences non fonctionnelles.

  • Optimisez la sélection des langages de programmation et des infrastructures au niveau du microservice. Utilisez plusieurs technologies comme il convient.

  • Hiérarchiser le Kit de développement logiciel (SDK) .NET pour optimiser la fiabilité et les performances. Les sdk Azure .NET offrent généralement davantage de fonctionnalités et sont fréquemment mis à jour.

Étape suivante

Passez en revue les considérations relatives à la plateforme d’application.