Tech Talk : Construire une architecture sans serveur dans AWS avec l'interaction des fonctions lambda (Partie 1)

Les fonctions en tant que service (FaaS) font partie du paradigme X-as-a-service, qui couvre la délégation de la gestion de la plateforme (PaaS), de l'infrastructure (IaaS) ou du logiciel (SaaS) à un fournisseur de services en nuage. Cela permet aux entreprises de se concentrer sur leur logique commerciale et de réduire les frais généraux.

L'idée derrière FaaS est que vous écrivez du code pour effectuer des tâches simples, et que le fournisseur de cloud s'occupe du reste. Bien entendu, la notion de "simple" dans ce contexte est subjective, et le fournisseur imposera des limites à ce que votre code peut réellement faire. Fondamentalement, il ne doit pas consommer beaucoup de mémoire et ne peut pas s'exécuter pendant des durées arbitrairement longues.

Les avantages de l'utilisation de FaaS au lieu de l'exécution du code dans une machine virtuelle sont les suivants :

  • Vous ne devez pas gérer l'infrastructure, ce qui est déjà un grand avantage.

  • Les événements déclenchent le code, ce qui simplifie le développement du logiciel.

  • En cas de pic d'activité, la mise à l'échelle du code est automatique, les fonctions s'exécutant en parallèle selon les besoins.

  • Le fournisseur de services en nuage vous facture ce que vous utilisez. Le prix a deux composantes : le temps d'exécution de votre fonction et la quantité de mémoire que vous allouez à votre code pour qu'il fasse son travail. Il n'y a pas de coûts supplémentaires pour les licences, la gestion des systèmes, la maintenance, l'assistance.

Ces caractéristiques font de FaaS un excellent outil pour les tâches dans lesquelles la demande de travail n'est pas constante dans le temps, par exemple, les tâches "de pointe" nécessitant de nombreuses ressources pendant une brève période de temps. Si votre code doit fonctionner 24 heures sur 24, 7 jours sur 7, ou avec de courtes périodes d'inactivité, la solution FaaS ne devrait pas être votre arme de prédilection. En revanche, pour les tâches simples qui ne doivent s'exécuter qu'occasionnellement, le FaaS est la voie à suivre. L'exploitation de services informatiques sans serveur soulagera vos maux de tête et de portefeuille en vous permettant d'éviter la maintenance et le paiement d'infrastructures sous-utilisées.

Le cas d'utilisation avec AWS

Chez Agilytic, nous avons récemment eu la chance de travailler sur un projet où nous avons construit une architecture sans serveur en utilisant les fonctions Lambda d'Amazon Web Services (AWS) (FaaS dans la nomenclature AWS), parmi d'autres services cloud. L'objectif du projet était la collecte et la classification de documents, en fonction de leur contenu, en s'appuyant sur différentes techniques : de la reconnaissance optique de caractères au résumé de texte. Récemment, nous avons également publié un article sur l'utilisation de Function App avec Azure pour construire des solutions de charge de travail intensive.

Nous avons décidé d'utiliser des fonctions Lambda spécialisées dans différentes sous-tâches de ce processus et d'interagir avec le stockage S3 et une base de données pour notre preuve de concept. AWS connecte ces Lambdas de manière séquentielle, chacune prenant la sortie de la précédente pour effectuer sa tâche. Dans cet article, nous voulons partager un peu de savoir-faire sur l'orchestration des fonctions Lambda.

Nous partons du principe que vous savez déjà comment créer des fonctions Lambda et gérer les rôles et les politiques IAM. Pour être concret, nous allons simplifier l'architecture que nous utilisons et connecter quelques fonctions Lambda, où chacune dépend de la sortie de la précédente pour pouvoir effectuer sa tâche spécialisée.

Nous utilisons la console AWS pour illustrer les différents thèmes de l'article, tandis que, pour le client, nous avons déployé toute l'architecture en tant qu'Infrastructure as Code, en utilisant terraform. L'utilisation de la console permet de créer automatiquement des rôles et, dans une certaine mesure, d'accorder des permissions. C'est une bonne chose pour le déploiement rapide, mais c'est une mauvaise chose pour la sécurité, que nous abordons dans la partie 2 de cet article.

Orchestration de fonctions avec AWS

Figure 1 : Vue d'ensemble de la fonction Lambda

Vous avez donc le code de votre première fonction Lambda et vous cherchez maintenant comment la déclencher, peut-être pour exécuter un test ou démarrer votre pipeline. Qu'est-ce que vous faites ? Commençons par les bases et supposons que vous exécutez un test. La première option est d'aller dans la console AWS et d'ouvrir l'aperçu de la fonction de votre Lambda, qui devrait ressembler à la figure 1.

Figure 2 : Événement test

Dans cette figure, vous voyez, surligné en jaune, le bouton de test. Il vous permettra de créer un événement personnalisé pour déclencher votre fonction. C'est facile. Si votre code a besoin d'un événement avec une clé "file" et une valeur "path", vous pouvez facilement l'écrire dans l'extrait de test, comme le montre la figure 2. Si, au contraire, votre code attend un événement provenant d'un autre service d'AWS, n'ayez crainte : il existe de nombreux modèles parmi lesquels vous pouvez choisir.

Après avoir exécuté le test, vous pourrez lire les journaux avec le résultat de l'invocation de votre fonction Lambda, vous indiquant si elle a réussi ou non. Dans ce dernier cas, il pointe vers la première erreur rencontrée, commençant ainsi la tâche de débogage.

Pourtant, cet article ne traite pas du débogage de vos Lambdas, mais de la façon de les faire communiquer entre eux. Voyons donc ce qui s'est passé ici. En bref, AWS a introduit le JSON que vous avez créé avec votre test dans l'argument event de la fonction lambda_handler de la figure 1 (surligné en bleu). C'est ainsi que les événements déclenchent la fonction Lambda.

La leçon est claire : la façon d'initier une Lambda est de lui fournir l'événement JSON (correctement formaté). Le runtime convertit automatiquement le JSON en un objet que votre code de programmation comprend.

Déclenchement automatique d'une fonction Lambda

Donc, AWS a fourni ce moyen facile de démarrer manuellement le travail d'une fonction serverless, mais soyons honnêtes, combien de cas d'utilisation vous permettent d'aller à la console AWS chaque fois que vous avez besoin que votre pipeline démarre, et de configurer un déclencheur manuel avec la bonne structure ? Vous pouvez avoir besoin d'un moyen de démarrer les jobs automatiquement, et généralement, dans l'un des deux cas suivants :

  1. Déclencher périodiquement une Lambda.

  2. Déclencher une Lambda en réponse à un événement qui s'est produit dans le cloud.

Les ingénieurs d'AWS y ont également pensé et ont mis en place un moyen pour que certains services AWS envoient des événements à vos fonctions Lambda. Pour déclencher périodiquement un Lambda dans AWS, vous définissez une règle AWS Cloudwatch sous "events" (nous savons, ce mot apparaît beaucoup trop dans cet article) dans la console AWS, et sélectionnez votre Lambda de choix comme cible pour cet événement (une fois de plus !), comme dans la figure 3.

Figure 3 : Mise en place d'un événement périodique

Pour les autres utilisations, il existe une manière plus centralisée de le faire. Dans la console AWS, dans la page de configuration de la Lambda (voir Figure 4), vous pouvez sélectionner le service à partir duquel vous voulez que votre Lambda soit déclenché et suivre les instructions pour configurer l'événement (au moment de la rédaction de ce document, vous pouvez choisir entre 16 services AWS et de nombreux autres services de partenaires). N'oubliez pas de toujours vérifier le modèle d'événement pour écrire le bon code ! (Rappel : vous les trouverez dans la partie surlignée en jaune de la figure 1).

Figure 4 : Déclenchement d'une Lambda

Déclencher une deuxième Lambda à partir de la première avec AWS

C'est très bien ! Vous avez appris à déclencher périodiquement ou par événement votre fonction Lambda. Maintenant, comment déclencher une deuxième fonction ? Une fonction Lambda peut-elle même déclencher une fonction Lambda ?

Si vous cliquez à nouveau sur le bouton "Ajouter un déclencheur" de la figure 4, vous ne verrez pas AWS Lambda écrit quelque part, mais désespérez ! Les personnes qui travaillent dans des services en nuage comme AWS sont intelligentes. Il n'est pas facile de les trouver dans une situation qu'ils n'ont pas encore imaginée (la question de savoir si nous sommes d'accord avec leurs choix de conception est une autre histoire, mais elle fera l'objet d'un autre article).

Par exemple, si votre première Lambda s'exécute tous les jours à midi, votre deuxième Lambda peut s'exécuter tous les jours à 12:20.

J'espère que vous avez ri, car vous avez compris la plaisanterie. Si ce n'est pas le cas, réfléchissons à nouveau au problème principal de ce que vous venez de lire (il y a plusieurs problèmes avec cette approche, mais ne les passons pas tous en revue). Comment la seconde Lambda recevrait-elle les informations traitées par la première dans ce scénario ?

Vous pouvez peut-être stocker ces informations dans une base de données ou un stockage intermédiaire et faire en sorte que la deuxième fonction les récupère automatiquement, mais cela ajoute de la complexité à votre code (et est une grande source d'erreurs et d'augmentation des factures). Une meilleure façon est de sauter l'intermédiaire et d'obtenir l'événement directement à partir de l'instruction de retour dans la fonction lambda_handler de la figure 1 (bien sûr, avec les informations appropriées dans le JSON !) C'est ainsi qu'une Lambda parle à une autre, après tout.

Invoquer une autre Lambda avec AWS

La première option pour faire communiquer deux Lambdas directement est d'utiliser le kit de développement logiciel AWS. Pour python, cela s'appelle boto3 et vous permet de gérer et d'interagir avec les ressources AWS à partir de votre code. Si vous jetez un coup d'œil à la documentation, vous verrez que vous pouvez configurer un client pour gérer les Lambdas et utiliser la méthode invoke pour déclencher une autre Lambda.

import boto3, json

client = boto3.client(‘lambda’)

client.invoke(FunctionName='ListenerLambda', InvocationType='Event', Payload=json.dumps({‘file’: ‘path’}))

(N'oubliez pas de consulter la documentation pour connaître la signification des différentes options et savoir s'il en existe d'autres !) Dans cet extrait de code, nous envoyons un événement avec la clé "file" et la valeur "path" à notre fonction d'écoute, nommée de manière appropriée "ListenerLambda". Le type d'invocation que nous avons défini ("Event") signifie que la fonction listener Lambda est déclenchée de manière asynchrone : nous n'attendons pas la réponse pour continuer à évaluer le code.

Cette solution simple fait l'affaire, mais elle n'est pas toujours (ou devrais-je dire rarement) un bon choix. Pour illustrer cela, imaginons les performances suivantes de nos Lambdas :

  1. La première fonction effectue une tâche simple et peut traiter 1 000 travaux par seconde.

  2. La seconde fonction a une tâche beaucoup plus difficile et peut traiter un travail par seconde.

Ce sont les ingrédients d'un goulot d'étranglement. En cinq secondes, nous pouvons envoyer 5 000 tâches à la deuxième fonction, et elle n'en traite que 5. Pire encore, le nombre maximal de tâches simultanées qu'une seule fonction Lambda peut exécuter (la concurrence) est de 1 000. Alors, qu'est-il arrivé aux presque 4 000 autres tâches ?

Ils ont disparu ! Comme vous pouvez l'imaginer, ce n'est pas bon. En général, vous ne devriez utiliser le SDK pour invoquer une fonction Lambda de manière asynchrone que si vous êtes sûr à 100 % que la tâche en aval sera toujours plus rapide que celle en amont. Si vous invoquez la fonction Lambda de manière synchrone, ce n'est pas un problème. Votre code se mettra en pause jusqu'à ce que l'invocation se termine. Cependant, vous serez également facturé pour le temps d'attente.

Conclusion

Nous avons montré les premières étapes de la construction d'architectures serverless efficaces dans le cloud avec les fonctions Lambda d'AWS. Dans la partie 2 de cet article Tech Talk, nous couvrons la façon dont le service SQS d'AWS, les fonctions Step et un ensemble restrictif de permissions agissent comme la base d'une architecture robuste et sécurisée. En outre, nous expliquons comment mettre en place la bonne solution pour votre organisation.

Précédent
Précédent

Tech Talk : Construire une architecture sans serveur dans AWS avec l'interaction des fonctions lambda (Partie 2)

Suivant
Suivant

Discussion technique : Recherche dans un grand champ de texte avec Elasticsearch et Kibana (Partie 2)