Les sources de l’idée
En regardant la doc de Micronaut je suis tombé sur un paragraphe qui m’a fait rêver : https://micronaut-projects.github.io/micronaut-aws/latest/guide/#apiProxy
Je me suis toujours demandé comment faire un backend d’application facile à configurer mais également pouvant être scalé facilement en cas de charge. J’ai l’impression d’avoir enfin trouvé une solution, voyons voir ce que ça vaut.
On va donc tenter de créer une API REST qu’on va faire tourner sur AWS Lambda qu’on va cacher derrière AWS API Gateway.
Pour ceux que ça intéresse les sources du projet sont disponibles sur Gitlab : https://gitlab.com/gautier-levert/micronaut-lambda-rest/
Créer le projet Micronaut
On commence donc gentiment à créer un projet Micronaut à l’aide de leur CLI, comme expliqué dans la documentation.
Premier petit problème, la feature décrite dans la doc n’existe pas. Il y a déjà une issue GitHub sur le sujet. Pas grave, on crée le projet quand même et on verra plus tard.
|
|
On ouvre notre projet dans notre IDE préféré et on va voir ce qu’on peut faire.
Le handler AWS Lambda
Comme expliqué plus haut la feature n’existe pas mais les modules existent bel et bien et il est possible de les ajouter au dépendances du projet.
|
|
La magie opère dans la classe : StreamLambdaHandler
|
|
On voit ici que cette classe, instancie une application Micronaut au complet et va nous permettre d’exécuter des requêtes au sein d’un handler lambda !
La configuration AWS
Maintenant il nous reste à configurer une fonction AWS Lambda et y déployer notre projet, on change de documentation et on se retrouve du côté de aws-serverless-java-container.
Ici on a besoin de SAM.
C’est un peu l’équivalent de serverless que vous avez déjà pu rencontrer si vous jouez un peu avec AWS Lambda
ou Google Cloud Functions
habituellement.
Je pars du principe qu’il est installé et configuré avec vox identifiants AWS (je vous renvoie vers la documentation officielle au besoin).
Là les ennuis commencent, le build de sam génère une archive trop grosse et les exemples de configuration ne fonctionnent pas…
Mais en creusant un peu j’ai fini pas comprendre le problème : https://github.com/awslabs/aws-lambda-builders/issues/138
J’ai finalement dû retirer les plugins Gradle shadow
et application
qui rentrait en conflit avec la procédure de build de SAM.
Pour le reste du fichier template, je me suis beaucoup inspiré de celui fourni dans le projet de démo : https://github.com/awslabs/aws-serverless-java-container/tree/master/samples/micronaut/pet-store
Je me suis principalement attaché à remplacer le runtime pour passer d’une compilation GraalVM à un projet java classique.
Voilà au final ce que ça donne :
|
|
Le déploiement
Voilà tout est en place, je compile, j’envoie et je laisse la magie opérer :
|
|
et ça marche !
J’appelle l’URL avec Postman et je reçois correctement le très attendu "Hello World"
.
Le problème : environ 6 secondes de délai. Je m’y attendais mais je m’attendais à un peu mieux… Heureusement les appels suivants ont des délais beaucoup plus raisonnables : 44ms, 56ms, 71ms, etc. Mais à chaque fois que le timeout de lambda arrive à terme et que le projet doit redémarrer, BOUM 6 secondes.
Du coup c’est mort ?
Non, le projet fonctionne très bien dans son ensemble et même si le premier chargement est long, on y gagne quand même pas mal de chose :
- un cout d’exécution ridicule : étant donné que le serveur tourne uniquement quand il exécute des requêtes.
- une montée en charge facile : par défaut AWS laisse tourner plus de 1000 instances simultanées.
- une descente de charge facile : les instances se coupent toutes seules.
- une disponibilité digne des plus grands : plus de coupure durant le déploiement, l’infrastructure d’Amazon pour gérer…
Par contre il ne faut pas oublier que tout ça ne fonctionne que si le reste de votre infrastructure (et en particulier la base de données) tient également la charge.
Donc si des requêtes de plusieurs secondes de temps en temps ne vous font pas peur, pourquoi pas.
Il ne faut pas oublier non plus que ce projet n’est qu’un simple Hello World, il est sûr que des projets plus gros vont avoir un temps de démarrage bien plus grand.
Pour que tout ça reste viable dans un environnement de production, il faudra tout d’abord limité la taille des projets et des dépendances, mais certainement aussi se pencher du côté de GraalVM pour compiler le projet en code natif.