Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article fournit des conseils pour améliorer les performances et la fiabilité de vos applications de fonction serverless . Pour obtenir un ensemble plus général de bonnes pratiques Azure Functions, consultez les meilleures pratiques d’Azure Functions.
Voici les meilleures pratiques de création et d’architecture de vos solutions serverless à l’aide d’Azure Functions.
Évitez les fonctions dont l’exécution prend beaucoup de longtemps
Ces fonctions peuvent provoquer des problèmes de délai d’attente inattendus. Pour en savoir plus sur les délais d’expiration d’un plan d’hébergement donné, consultez la durée du délai d’expiration de l’application de fonction.
Une fonction peut devenir volumineuse en raison de nombreuses dépendances Node.js. L’importation de dépendances peut également entraîner une augmentation des temps de chargement qui entraînent des délais d’attente inattendus. Les dépendances sont chargées tant explicitement qu’implicitement. Un seul module chargé par votre code peut charger ses propres modules supplémentaires.
Dans la mesure du possible, refactorisez les fonctions volumineuses en jeux de fonctions plus petits qui fonctionnent ensemble et retournent rapidement des réponses. Par exemple, une fonction de webhook ou de déclencheur HTTP peut nécessiter une réponse d’accusé de réception dans une certaine limite de temps ; il est courant que les webhooks nécessitent une réponse immédiate. Vous pouvez transmettre la charge utile du déclencheur HTTP à une file d'attente pour qu'elle soit traitée par une fonction déclencheur de file d'attente. Cette approche vous permet de différer le travail réel et de retourner une réponse immédiate.
Assurez-vous que les tâches en arrière-plan se terminent
Lorsque votre fonction démarre des tâches, des rappels, des threads, des processus, ils doivent être terminés avant le retour du code de votre fonction. Étant donné que Functions ne suit pas ces threads d’arrière-plan, l’arrêt du site peut se produire indépendamment de l’état du thread d’arrière-plan, ce qui peut entraîner un comportement inattendu dans vos fonctions.
Par exemple, si une fonction démarre une tâche en arrière-plan et retourne une réponse réussie avant la fin de la tâche, le runtime Functions considère l’exécution comme ayant réussi, quel que soit le résultat de la tâche en arrière-plan. Si cette tâche en arrière-plan effectue un travail essentiel, elle peut être interrompue par la fermeture du site, laissant ce travail dans un état inconnu.
Communication entre fonctions
Durable Functions et Azure Logic Apps sont conçus pour gérer les transitions d’état et la communication entre plusieurs fonctions.
Si vous n’utilisez pas Durable Functions ou Logic Apps pour l’intégrer à plusieurs fonctions, il est préférable d’utiliser des files d’attente de stockage pour la communication entre fonctions. La principale raison est que les files d’attente de stockage sont moins coûteuses et beaucoup plus faciles à approvisionner que d’autres options de stockage.
Les messages individuels d’une file d’attente de stockage sont limités à 64 Ko. Si vous devez transmettre des messages plus volumineux entre les fonctions, une file d’attente Azure Service Bus peut être utilisée pour prendre en charge les tailles de messages allant jusqu’à 256 Ko dans le niveau Standard, et jusqu’à 100 Mo dans le niveau Premium.
Les rubriques Service Bus sont utiles si vous avez besoin d’un filtrage des messages avant le traitement.
Les hubs d’événements sont utiles pour prendre en charge les communications à volume élevé.
Écrire des fonctions sans état
Les fonctions doivent être sans état et idempotentes si possible. Associez toutes les informations d’état requises à vos données. Par exemple, une commande en cours de traitement aurait probablement un membre associé state . Une fonction peut traiter un ordre basé sur cet état alors que la fonction elle-même reste sans état.
Les fonctions idempotentes sont particulièrement recommandées avec les déclencheurs à minuterie. Par exemple, si vous avez quelque chose qui doit absolument s’exécuter une fois par jour, écrivez-le afin qu’il puisse s’exécuter à tout moment pendant la journée avec les mêmes résultats. La fonction peut s'arrêter lorsqu'il n'y a pas de travail pour un jour donné. En outre, si une exécution précédente n’a pas pu se terminer, la prochaine exécution doit reprendre là où elle s’est arrêtée. Cela est particulièrement important pour les liaisons basées sur les messages qui réessayent en cas d’échec. Pour plus d’informations, consultez Conception d’Azure Functions pour une entrée identique.
Écrire des fonctions défensives
Supposons que votre fonction peut rencontrer une exception à tout moment. Concevez vos fonctions avec la possibilité de continuer à partir d’un point d’échec précédent pendant l’exécution suivante. Considérez un scénario qui nécessite les actions suivantes :
- Recherchez 10 000 lignes dans une base de données.
- Créez un message de file d'attente pour chacune de ces lignes de données afin de les traiter ultérieurement dans le processus.
Selon la complexité de votre système, vous pouvez avoir : les services en aval impliqués se comportent mal, les pannes réseau ou les limites de quota atteintes, etc. Tous ces éléments peuvent affecter votre fonction à tout moment. Vous devez concevoir vos fonctions pour qu'elles soient prêtes à gérer cela.
Comment votre code réagit-il si une défaillance se produit après l’insertion de 5 000 de ces éléments dans une file d’attente pour traitement ? Effectuez le suivi des éléments d’un ensemble que vous avez terminé. Sinon, vous pouvez les insérer à nouveau la prochaine fois. Cette double insertion peut avoir un impact sérieux sur votre flux de travail, ce qui rend vos fonctions idempotentes.
Si un élément de file d’attente a déjà été traité, permettez à votre fonction d’être une absence d’opération.
Tirez parti des mesures défensives déjà fournies pour les composants que vous utilisez dans la plateforme Azure Functions. Par exemple, consultez Gestion des messages de file d'attente empoisonnés dans la documentation relative aux déclencheurs et liaisons des files d’attente de Stockage Azure.
Pour les fonctions basées sur HTTP, envisagez des stratégies de gestion des versions d’API avec Gestion des API Azure. Par exemple, si vous devez mettre à jour votre application de fonction basée sur HTTP, déployez la nouvelle mise à jour sur une application de fonction distincte et utilisez des révisions ou des versions de Gestion des API pour diriger les clients vers la nouvelle version ou révision. Une fois que tous les clients utilisent la version ou la révision et qu’aucune autre exécution n’est laissée sur l’application de fonction précédente, vous pouvez déprovisionner l’application de fonction précédente.
Bonnes pratiques de l’organisation des fonctions
Dans le cadre de votre solution, vous pouvez développer et publier plusieurs fonctions. Ces fonctions sont souvent combinées en une application de fonction unique, mais elles peuvent également être exécutées dans des applications de fonction distinctes. Dans les plans d’hébergement Premium et dédiés (App Service), plusieurs applications de fonction peuvent également partager les mêmes ressources en s’exécutant dans le même plan. La façon dont vous regroupez vos fonctions et vos applications de fonction peut impacter les performances, la mise à l’échelle, la configuration, le déploiement et la sécurité de votre solution globale. Il n’existe pas de règles qui s’appliquent à chaque scénario. Tenez donc compte des informations contenues dans cette section lors de la planification et du développement de vos fonctions.
Organiser les fonctions pour les performances et la mise à l’échelle
Chaque fonction que vous créez a une empreinte mémoire. Bien que cette empreinte soit généralement petite, avoir trop de fonctions au sein d’une application de fonction peut entraîner un démarrage plus lent de votre application sur de nouvelles instances. Cela signifie également que l’utilisation globale de la mémoire de votre application de fonction peut être plus élevée. Il est difficile de dire combien de fonctions doivent se trouver dans une seule application, qui dépend de votre charge de travail particulière. Toutefois, si votre fonction stocke beaucoup de données en mémoire, envisagez d’avoir moins de fonctions dans une seule application.
Si vous exécutez plusieurs applications de fonction dans un plan Premium unique ou dédié (App Service), ces applications partagent toutes les mêmes ressources allouées au plan. Si vous avez une application de fonction qui a une exigence de mémoire beaucoup plus élevée que les autres, elle utilise une quantité disproportionnée de ressources mémoire sur chaque instance sur laquelle l’application est déployée. Étant donné que cela peut laisser moins de mémoire disponible pour les autres applications sur chaque instance, vous pouvez exécuter une application de fonction à mémoire élevée comme celle-ci dans son propre plan d’hébergement distinct.
Remarque
Lorsque vous utilisez le plan Consommation, nous vous recommandons de toujours placer chaque application dans son propre plan, car les applications sont mises à l’échelle indépendamment de toute façon. Pour plus d’informations, consultez Plusieurs applications dans le même plan.
Déterminez si vous souhaitez regrouper des fonctions avec différents profils de charge. Par exemple, si vous avez une fonction qui traite plusieurs milliers de messages de file d’attente, et une autre qui est uniquement appelée occasionnellement, mais qui a des besoins en mémoire élevés, vous pouvez les déployer dans des applications de fonction distinctes afin qu’ils obtiennent leurs propres ensembles de ressources et qu’ils s’adaptent indépendamment les uns des autres.
Organiser les fonctions pour la configuration et le déploiement
Les applications de fonction ont un host.json fichier, qui est utilisé pour configurer le comportement avancé des déclencheurs de fonction et le runtime Azure Functions. Les modifications apportées au host.json fichier s’appliquent à toutes les fonctions de l’application. Si vous avez certaines fonctions qui ont besoin de configurations personnalisées, envisagez de les déplacer dans leur propre application de fonction.
Toutes les fonctions de votre projet local sont déployées ensemble sous la forme d’un ensemble de fichiers sur votre application de fonction dans Azure. Vous devrez peut-être déployer des fonctions individuelles séparément ou utiliser des fonctionnalités telles que des emplacements de déploiement pour certaines fonctions et non d’autres. Dans ce cas, vous devez déployer ces fonctions (dans des projets de code distincts) sur différentes applications de fonction.
Organiser les fonctions par privilège
Les chaînes de connexion et d’autres informations d’identification stockées dans les paramètres de l’application donnent à toutes les fonctions de l’application de fonction le même jeu d’autorisations dans la ressource associée. Envisagez de réduire le nombre de fonctions ayant accès à des informations d’identification spécifiques en déplaçant des fonctions qui n’utilisent pas lesdites informations d’identification vers une application de fonction distincte. Vous pouvez toujours utiliser des techniques telles que le chaînage de fonctions pour passer des données entre des fonctions dans différentes applications de fonction.
Meilleures pratiques en matière d’extensibilité
Il existe un certain nombre de facteurs qui affectent la façon dont les instances de votre application de fonction sont mises à l’échelle. Les détails sont fournis dans la documentation relative à la mise à l’échelle des fonctions. Voici quelques bonnes pratiques pour garantir une scalabilité optimale d’une application de fonction.
Partager et gérer des connexions
Réutilisez les connexions à des ressources externes dans la mesure du possible. Découvrez comment gérer les connexions dans Azure Functions.
Éviter le partage des comptes de stockage
Lorsque vous créez une application de fonction, vous devez l’associer à un compte de stockage. La connexion au compte de stockage est conservée dans le paramètre d’application AzureWebJobsStorage.
Pour optimiser les performances, utilisez un compte de stockage différent pour chaque application de fonction. Cette approche est particulièrement importante lorsque vous avez des Durable Functions ou des fonctions déclenchées par Event Hubs, qui génèrent toutes deux un volume élevé de transactions de stockage. Lorsque votre logique d’application interagit avec le stockage Azure, soit directement (à l’aide du SDK Stockage), soit via l’une des liaisons de stockage, vous devez utiliser un compte de stockage dédié. Par exemple, si vous avez une fonction déclenchée par un hub d’événements qui écrit des données dans le stockage d’objets blob, utilisez deux comptes de stockage : un pour l’application de fonction et un autre pour les objets blob que la fonction stocke.
Ne pas mélanger code de test et code de production dans la même application de fonction
Les fonctions d’une application de fonction partagent des ressources. Par exemple, la mémoire est partagée. Si vous utilisez une application de fonction en production, n’ajoutez pas de fonctions et de ressources associées aux tests. Cela peut entraîner une surcharge inattendue pendant l’exécution du code de production.
Faites attention à ce que vous chargez dans vos applications de fonctions en production. La mémoire est moyenne sur chaque fonction de l’application.
Si vous avez un assembly partagé référencé dans plusieurs fonctions .NET, placez-le dans un dossier partagé commun. Sinon, vous pouvez déployer accidentellement plusieurs versions du même binaire qui se comportent différemment entre les fonctions.
N’utilisez pas la journalisation détaillée dans le code de production, ce qui a un impact négatif sur les performances.
Utiliser du code asynchrone tout en évitant de bloquer les appels
La programmation asynchrone est une bonne pratique recommandée, en particulier lors du blocage des opérations d’E/S.
En C#, évitez toujours de référer à la propriété Result ou d'appeler la méthode Wait sur une instance de Task. Cette approche peut mener à un épuisement des threads.
Conseil / Astuce
Si vous envisagez d’utiliser les liaisons HTTP ou WebHook, prévoyez d’éviter l’épuisement du port qui peut résulter d’une instanciation incorrecte de HttpClient. Pour plus d’informations, consultez How to manage connections in Azure Functions (Comment gérer des connexions dans Azure Functions).
Utiliser plusieurs processus de travail
Par défaut, n’importe quelle instance hôte pour Functions utilise un seul processus de travail. Pour améliorer les performances, en particulier avec des runtimes monothreads comme Python, utilisez la FUNCTIONS_WORKER_PROCESS_COUNT pour augmenter le nombre de processus de travail par hôte (jusqu’à 10). Azure Functions essaie ensuite de distribuer uniformément les appels de fonction simultanés à ces différents Workers.
FUNCTIONS_WORKER_PROCESS_COUNT s’applique à chaque hôte créé par Functions lors du scale-out de votre application pour répondre à la demande.
Recevoir des messages par lots chaque fois que possible
Certains déclencheurs comme Event Hub permettent de recevoir un lot de messages sur un appel unique. Le traitement par lots de messages offre de meilleures performances. Vous pouvez configurer la taille maximale du lot dans le host.json fichier, comme indiqué dans la documentation de référencehost.json
Pour les fonctions C#, vous pouvez remplacer le type par un tableau fortement typé. Par exemple, au lieu de EventData sensorEvent, la signature de méthode pourrait être EventData[] sensorEvent. Pour d'autres langues, vous devez définir explicitement la propriété de cardinalité de function.json à many afin d'activer le traitement par lots, comme indiqué ici .
Configurer les comportements d’hôte pour mieux gérer l’accès concurrentiel
Le fichier host.json de l'application fonctionnelle permet la configuration du runtime hôte et des comportements de déclenchement. En plus des comportements de traitement par lot, vous pouvez gérer l’accès concurrentiel d’un certain nombre de déclencheurs. Souvent l’ajustement des valeurs de ces options peut permettre la mise à l’échelle adéquate de chaque instance face aux demandes des fonctions appelées.
Les paramètres du fichier host.json s’appliquent à toutes les fonctions de l’application, dans une seule instance de la fonction. Par exemple, si vous aviez une application de fonction dotée de deux fonctions HTTP avec une valeur pour les demandes simultanées maxConcurrentRequests définie sur 25, une requête à l’un des déclencheurs HTTP serait comptabilisée dans les 25 demandes simultanées partagées. Lorsque cette application de fonction est mise à l’échelle à 10 instances, les dix fonctions autorisent efficacement 250 requêtes simultanées (10 instances * 25 requêtes simultanées par instance).
D’autres options de configuration d’hôte se trouvent dans l’article de configurationhost.json.
Étapes suivantes
Pour plus d’informations, consultez les ressources suivantes :