Chapitre 1: Introduction aux Microservices
đŻ Objectifs du Chapitreâ
- Comprendre la différence entre monolithe et microservices
- Identifier les avantages et inconvénients de chaque approche
- Découvrir les patterns essentiels des microservices
- MaĂźtriser les principes de la 12-Factor App
- Savoir quand choisir quelle architecture
1. Architecture Monolithiqueâ
1.1 DĂ©finitionâ
Un monolithe est une application oĂč toutes les fonctionnalitĂ©s sont dĂ©ployĂ©es ensemble dans un seul processus.
1.2 Exemple: E-Commerce Monolithiqueâ
// Structure typique d'un monolithe
src/main/java/com/ecommerce/
âââ EcommerceApplication.java
âââ config/
â âââ SecurityConfig.java
âââ controller/
â âââ UserController.java
â âââ ProductController.java
â âââ OrderController.java
â âââ PaymentController.java
â âââ InventoryController.java
âââ service/
â âââ UserService.java
â âââ ProductService.java
â âââ OrderService.java
â âââ PaymentService.java
â âââ InventoryService.java
âââ repository/
â âââ UserRepository.java
â âââ ProductRepository.java
â âââ OrderRepository.java
â âââ ...
âââ model/
âââ User.java
âââ Product.java
âââ Order.java
âââ ...
1.3 Avantages du Monolitheâ
| Avantage | Explication |
|---|---|
| Simplicité de développement | Un seul projet, un seul IDE |
| Déploiement simple | Un seul JAR/WAR à déployer |
| Tests faciles | Tests d'intégration simples |
| Transactions ACID | Une seule BD = transactions faciles |
| Debugging simple | Stack trace complĂšte |
| Performance locale | Pas de latence réseau entre modules |
| Refactoring facile | IDE peut renommer partout |
1.4 InconvĂ©nients du Monolitheâ
| Inconvénient | Explication |
|---|---|
| Scaling tout ou rien | Impossible de scaler un seul module |
| Déploiement risqué | Un bug = toute l'app down |
| Stack unique | Tout en Java (ou autre) |
| Temps de build long | Recompiler tout Ă chaque fois |
| Conflits d'équipe | Merges difficiles sur un gros projet |
| Dette technique | Difficile Ă moderniser |
| Onboarding long | Nouveau dev doit tout comprendre |
1.5 Quand le Monolithe Devient ProblĂ©matiqueâ
Année 1: Startup
- 3 développeurs
- 50K lignes de code
- Déploiement: 5 minutes
â Monolithe PARFAIT â
Année 3: Croissance
- 30 développeurs
- 500K lignes de code
- Déploiement: 45 minutes
- Conflits Git quotidiens
â Monolithe devient un frein â ïž
Année 5: Scale
- 100 développeurs
- 2M lignes de code
- Déploiement: 2 heures
- Black Friday: tout crash
â Monolithe = "Big Ball of Mud" â
2. Architecture Microservicesâ
2.1 DĂ©finitionâ
Les microservices sont une approche oĂč l'application est divisĂ©e en petits services autonomes, chacun:
- Déployable indépendamment
- Avec sa propre base de données
- Communiquant via API (HTTP/REST ou messaging)
- Géré par une petite équipe
2.2 CaractĂ©ristiques ClĂ©sâ
1. Single Responsibilityâ
Chaque service fait UNE chose bien:
- user-service: gestion utilisateurs UNIQUEMENT
- order-service: gestion commandes UNIQUEMENT
- inventory-service: gestion stock UNIQUEMENT
2. Autonomieâ
Chaque service:
- A son propre repo Git
- A sa propre BD (Database per Service)
- A son propre pipeline CI/CD
- Peut ĂȘtre dĂ©ployĂ© seul
- Peut utiliser une techno différente
3. Communicationâ
Synchrone (HTTP/REST):
- Client attend la réponse
- Simple mais couplant
Asynchrone (Messaging):
- Fire and forget
- Découplé mais complexe
2.3 Avantages des Microservicesâ
| Avantage | Explication |
|---|---|
| Scaling ciblé | Scaler uniquement le service qui en a besoin |
| Isolation des pannes | Un service down â tout down |
| Déploiement indépendant | Déployer 10x par jour par service |
| Polyglotte | Java, Node, Python, Go... selon le besoin |
| Ăquipes autonomes | "You build it, you run it" |
| ĂvolutivitĂ© | Ajouter un service sans toucher aux autres |
| Modernisation | Réécrire un service à la fois |
2.4 InconvĂ©nients des Microservicesâ
| Inconvénient | Explication |
|---|---|
| Complexité distribuée | Debugging difficile |
| Latence réseau | Appels HTTP entre services |
| Transactions distribuées | ACID impossible, Sagas nécessaires |
| Cohérence éventuelle | Données pas immédiatement synchronisées |
| Opérations complexes | Monitoring, logging, tracing |
| Coût infrastructure | Plus de serveurs, plus de BDs |
| Overhead | Chaque service = overhead mémoire |
3. Comparaison DĂ©taillĂ©eâ
3.1 Tableau Comparatifâ
| CritĂšre | Monolithe | Microservices |
|---|---|---|
| ComplexitĂ© initiale | Faible | ĂlevĂ©e |
| ComplexitĂ© Ă long terme | ĂlevĂ©e | MaĂźtrisĂ©e |
| Déploiement | Tout ou rien | Indépendant |
| Scaling | Vertical | Horizontal |
| Technologie | Unique | Polyglotte |
| Ăquipe | Une Ă©quipe | Ăquipes par service |
| Base de données | Partagée | Par service |
| Transactions | ACID simple | Sagas (complexe) |
| Debugging | Simple | Distribué (complexe) |
| Latence | Faible | Plus élevée |
| CoĂ»t initial | Faible | ĂlevĂ© |
| Time to market | Rapide au début | Plus lent au début |
3.2 CritĂšres de DĂ©cisionâ
4. Patterns Microservices Essentielsâ
4.1 API Gateway Patternâ
Responsabilités:
- Routing des requĂȘtes
- Authentication/Authorization
- Rate Limiting
- Load Balancing
- SSL Termination
- Caching
- Request/Response transformation
4.2 Service Discovery Patternâ
Comment ça marche:
- Service dĂ©marre â s'enregistre auprĂšs d'Eureka
- Client veut appeler Service A
- Client demande Ă Eureka: "OĂč est Service A?"
- Eureka retourne la liste des instances
- Client choisit une instance (load balancing client-side)
- Client appelle directement l'instance
4.3 Circuit Breaker Patternâ
Ătats:
- CLOSED: Normal, les appels passent
- OPEN: Trop d'Ă©checs, appels bloquĂ©s â fallback
- HALF-OPEN: Test si le service est revenu
// Exemple avec Resilience4j
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
public User getUser(Long id) {
return userServiceClient.getUser(id); // Appel distant
}
public User getUserFallback(Long id, Exception ex) {
return new User(id, "Unknown", "Service temporarily unavailable");
}
4.4 Saga Pattern (Transactions DistribuĂ©es)â
Dans un monolithe:
@Transactional
public void createOrder(Order order) {
orderRepository.save(order); // â
inventoryService.reserve(order); // â
paymentService.charge(order); // â Ăchec â ROLLBACK tout
}
Avec microservices (Saga Choreography):
4.5 Event Sourcing & CQRSâ
ĂvĂ©nements au lieu d'Ă©tats:
// Au lieu de: UPDATE orders SET status = 'SHIPPED'
// On stocke des événements:
OrderCreated { orderId: 1, items: [...], timestamp: ... }
PaymentReceived { orderId: 1, amount: 100, timestamp: ... }
OrderShipped { orderId: 1, trackingNumber: "ABC123", timestamp: ... }
5. The Twelve-Factor Appâ
Les 12 facteurs sont des principes pour construire des applications cloud-native:
Les 12 Facteursâ
| # | Facteur | Description | Application Spring Boot |
|---|---|---|---|
| 1 | Codebase | Un repo = une app | Un repo Git par service |
| 2 | Dependencies | Déclarer explicitement | pom.xml / build.gradle |
| 3 | Config | Config dans l'environnement | application.yml + env vars |
| 4 | Backing Services | Traiter comme ressources attachées | DataSource configurable |
| 5 | Build, Release, Run | Séparer les étapes | CI/CD pipeline |
| 6 | Processes | Stateless | Session dans Redis |
| 7 | Port Binding | Exporter via port | Embedded Tomcat |
| 8 | Concurrency | Scale via processus | Instances multiples |
| 9 | Disposability | DĂ©marrage/arrĂȘt rapide | Graceful shutdown |
| 10 | Dev/Prod Parity | Environnements similaires | Docker |
| 11 | Logs | Traiter comme flux | stdout â collecteur |
| 12 | Admin Processes | TĂąches admin one-off | Spring Batch |
Exemple: Facteur 3 - Configurationâ
# â Mauvais: Config hardcodĂ©e
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret123
# â
Bon: Config externalisée
spring:
datasource:
url: ${DATABASE_URL}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
Exemple: Facteur 6 - Processes Statelessâ
// â Mauvais: Ătat en mĂ©moire
@RestController
public class CartController {
private Map<Long, Cart> carts = new HashMap<>(); // Ătat local!
@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
carts.computeIfAbsent(userId, Cart::new).add(item);
}
}
// â
Bon: Ătat externalisĂ© (Redis)
@RestController
public class CartController {
private final RedisTemplate<String, Cart> redis;
@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
String key = "cart:" + userId;
Cart cart = redis.opsForValue().get(key);
if (cart == null) cart = new Cart();
cart.add(item);
redis.opsForValue().set(key, cart);
}
}
6. Domain-Driven Design (DDD) et Microservicesâ
6.1 Bounded Contextâ
Le Bounded Context définit les frontiÚres d'un microservice:
6.2 MĂȘme Concept, Contextes DiffĂ©rentsâ
// Dans Sales Context
public class Customer {
private Long id;
private String name;
private String email;
private List<Order> orders;
private LoyaltyLevel loyaltyLevel;
}
// Dans Shipping Context
public class Customer {
private Long id;
private String name;
private Address shippingAddress;
private String phoneNumber;
}
// Dans Billing Context
public class Customer {
private Long id;
private String name;
private PaymentMethod defaultPaymentMethod;
private BillingAddress billingAddress;
}
7. Anti-Patterns Ă Ăviterâ
7.1 Distributed Monolithâ
â ANTI-PATTERN: Monolithe distribuĂ©
- 10 services qui DOIVENT ĂȘtre dĂ©ployĂ©s ensemble
- Schéma de BD partagé
- Couplage fort entre services
- Pire des deux mondes!
7.2 Nano-Servicesâ
â ANTI-PATTERN: Services trop petits
- Un service par entité
- UserService, UserAddressService, UserPreferenceService
- Overhead énorme
- Transactions impossibles
7.3 Shared Databaseâ
â ANTI-PATTERN: Base de donnĂ©es partagĂ©e
Service A âââŹââ> PostgreSQL <âââŹââ Service B
â â
âââ> orders table <â
ProblĂšme:
- Couplage fort via le schéma
- Impossible de modifier une table
- Transactions croisées tentantes
7.4 Sync Everywhereâ
â ANTI-PATTERN: Tout en synchrone
Order Service
â HTTP sync
Inventory Service
â HTTP sync
Payment Service
â HTTP sync
Notification Service
ProblĂšme:
- Latence cumulée
- Un service lent = tout lent
- Cascade failures
8. Migration Monolithe â Microservicesâ
8.1 StratĂ©gie: Strangler Fig Patternâ
8.2 Ătapes de Migrationâ
- Identifier les Bounded Contexts dans le monolithe
- Commencer par le moins risqué (ex: notifications)
- Extraire dans un nouveau service
- Router via API Gateway
- Supprimer l'ancien code du monolithe
- Répéter pour le prochain contexte
9. RĂ©sumĂ©â
Points ClĂ©sâ
â
Monolithe = Simple mais ne scale pas
â
Microservices = Complexe mais flexible
â
Commencer monolithe si possible
â
Migrer quand le monolithe devient un frein
â
12-Factor App = bonnes pratiques cloud-native
â
DDD = aide à définir les frontiÚres
â
Patterns = Circuit Breaker, Saga, Event Sourcing
Checklist Avant Microservicesâ
- Ăquipe expĂ©rimentĂ©e en DevOps?
- Infrastructure Kubernetes/Docker?
- Monitoring et logging centralisés?
- CI/CD mature?
- Bounded Contexts bien définis?
- ProblÚmes réels de scaling?
10. Quiz de Validationâ
Question 1â
Quel pattern permet d'éviter la cascade de pannes entre services?
Voir la réponse
Circuit Breaker - Il détecte les échecs et "ouvre" le circuit pour retourner un fallback immédiatement au lieu d'attendre des timeouts.
Question 2â
Pourquoi "Database per Service" est important?
Voir la réponse
- Découplage: Chaque service peut évoluer son schéma indépendamment
- Autonomie: Pas de dépendance sur un DBA central
- Technologie: PostgreSQL pour un service, MongoDB pour un autre
- Ăvite le couplage cachĂ© via le schĂ©ma partagĂ©
Question 3â
Qu'est-ce qu'un "Distributed Monolith"?
Voir la réponse
Un anti-pattern oĂč on a plusieurs services mais:
- Ils doivent ĂȘtre dĂ©ployĂ©s ensemble
- Ils partagent une base de données
- Ils sont fortement couplés
On a la complexité des microservices SANS les avantages.