TP10 : High Scalability on Woodytoys
Introduction
Jusqu’ici, nous avons vu des techniques pour rendre notre infrastructure plus robuste aux pannes (en rajoutant de la redondance notamment) et capable de traiter plus de trafic (en rajoutant de la cache, un CDN, un load balancer, … ). Maintenant, nous allons nous attarder sur la “scalabilité” de notre application en adoptant une structure de micro-services. Nous allons aussi mettre en place un Messages Broker pour permettre une communication asynchrone entre les différents (micro) services. Notez que les techniques peuvent parfois être les même entre les différentes problématiques (haute disnonibilité vs haute performance vs haute scalabilité), ce qui est tout à fait normal étant donné qu’elles sont fortement liées.
La haute scalabilité est la capacité d’un système à s’adapter à une augmentation ou une diminution de la demande en ressources de manière fluide et efficace. Cela signifie que le système peut gérer un plus grand nombre d’utilisateurs, de transactions ou de données sans compromettre les performances ou la disponibilité.
Nous allons continuer sur la stack présentée au précédent TP sur cette page github , combinée à ce qui a été rajouté lors du TP précédent (Cache et CDN).
1. Microservices
Pour rendre notre application ‘scalable’, nous allons la diviser en microservices.
Les micro-services étant découplés et indépendants, il est possible de les “scaler” individuellement en fonction de leur charge respective. Cela permet d’allouer des ressources de manière plus précise et efficace aux services les plus sollicités, sans gaspiller des ressources pour les services moins utilisés.
Réfléchissez à la division possible entre les différents services. Vous pouvez répartir les endpoints en plusieurs applications Flask et les ‘recontenairiser’ ou, dans un premier temps, vous pouvez juste utiliser la même image docker pour les différents services.
Comment faire maintenant pour que votre nginx redirige vers le bon service en fonction du endpoint demandé ? Voici un petit bout de configuration nginx qui devrait vous mettre sur la piste :
server {
listen 80;
server_name api.example.com;
# Redirection des endpoints /api/users/* vers le service d'authentification
location ^~ /api/users/(.*) {
proxy_pass http://auth-service:8082/$1;
}
# Configuration par défaut pour les autres requêtes
location / {
root /var/www/html;
index index.html index.htm;
}
}
Adaptez la config de Nginx pour qu’il redirige sur le bon service.
Bien que les microservices présentent de nombreux avantages en matière de scalabilité, il est important de noter qu’ils ne constituent pas une solution miracle. La migration vers une architecture de microservices implique une planification, une conception et une mise en œuvre soigneuses. De plus, cela rajoute de la complexité (qui n’est parfois pas nécessaire).
2. Communication Asynchrone
Dans le contexte des micro-services et de la haute scalabilité, la communication asynchrone (entre les services) joue un rôle crucial.
Dans le cadre de ce TP, nous allons utiliser RabbitMQ, qui est un service de messagerie basé sur des files d’attente : des (micro)services peuvent envoyer des messages et d’autres peuvent venir lire ses messages (pour faire des choses en fonction).
Ce système (RabbitMQ ou autre) permet de :
- Découpler vos services: vos micro-services deviennent donc plus indépendants.
- De rendre votre système plus résilient: si l’un des services lâche, votre application peut continuer.
- De gérer les pics (temporaire) de demande : car un pic remplit juste la file d’attente sans ‘noyer’ le système.
- D’avoir une scalabilité indépendante: Par exemple un service peut remplir la file et 10 autres peuvent en traiter les messages.
Sur base de ces éléments, identifiez où vous pourriez tirez profit de ce mécanisme (il y a des indices dans le code).
N’hésitez pas à prendre connaissance de ce tutoriel RabbitMQ : ‘Hello World’ officiel en python
Si ca ne marche pas ou que RabbitMQ ne vous inspire pas, vous pouvez utiliser Mousquitto (si vous aimez le MQTT) ou Redis ou …
3. API Gateway
Une API Gateway bien conçue est un élément essentiel pour atteindre une haute scalabilité dans les architectures d’API modernes. Elle offre une abstraction simplifiée, une sécurité renforcée, une gestion efficace du trafic et une évolutivité pour répondre aux demandes croissantes.
Plusieurs solutions spécifiques existety, mais pour pas complexifier d’avantage ce TP, nous resterons sur Nginx (et le loadbalancer intégré à Docker Swarm), mais dans sa version gratuite, Nginx est limité.
Vous avez déjà implémenté avec Nginx plusieurs aspects important qu’on retrouve dans une API Gateway, tels que le https, les redirections en fonction des URLs. Une API gateway a d’autres éléments importants autour de la sécurité et la gestion des sessions, mais ils sont soit trop compliqués pour ce TP, soit non disponibles dans Nginx (version gratuite).
Dans cet exercice, il vous est demandé de protéger votre API contre une utilisation abusive, en limitant le nombre de requêtes par minute.
Protégez (et testez) votre api contre une utilisation abusive, en implémentant ceci
C’est un bonus particulier que je vous propose (il faut donc voir avec votre professeur les détails), mais, si le sujet vous intéresse, il y a moyen d’améliorer le code de Woodytoys pour le rendre propice à plus d’exercices dans le thème vu ces 3 dernier TPs. Attention: il ne s’agit donc pas de résoudre un exercice mais de le créer. Vous pouvez prendre une thématique (exemple communication asynchrone) et adapter le code pour qu’il se prête bien à cet exercice.