Aller au contenu principal

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​

AvantageExplication
Simplicité de développementUn seul projet, un seul IDE
Déploiement simpleUn seul JAR/WAR à déployer
Tests facilesTests d'intégration simples
Transactions ACIDUne seule BD = transactions faciles
Debugging simpleStack trace complĂšte
Performance localePas de latence réseau entre modules
Refactoring facileIDE peut renommer partout

1.4 InconvĂ©nients du Monolithe​

InconvénientExplication
Scaling tout ou rienImpossible de scaler un seul module
Déploiement risquéUn bug = toute l'app down
Stack uniqueTout en Java (ou autre)
Temps de build longRecompiler tout Ă  chaque fois
Conflits d'équipeMerges difficiles sur un gros projet
Dette techniqueDifficile Ă  moderniser
Onboarding longNouveau 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​

AvantageExplication
Scaling cibléScaler uniquement le service qui en a besoin
Isolation des pannesUn service down ≠ tout down
Déploiement indépendantDéployer 10x par jour par service
PolyglotteJava, Node, Python, Go... selon le besoin
Équipes autonomes"You build it, you run it"
ÉvolutivitĂ©Ajouter un service sans toucher aux autres
ModernisationRéécrire un service à la fois

2.4 InconvĂ©nients des Microservices​

InconvénientExplication
Complexité distribuéeDebugging difficile
Latence réseauAppels HTTP entre services
Transactions distribuéesACID impossible, Sagas nécessaires
Cohérence éventuelleDonnées pas immédiatement synchronisées
Opérations complexesMonitoring, logging, tracing
Coût infrastructurePlus de serveurs, plus de BDs
OverheadChaque service = overhead mémoire

3. Comparaison DĂ©taillĂ©e​

3.1 Tableau Comparatif​

CritĂšreMonolitheMicroservices
ComplexitĂ© initialeFaibleÉlevĂ©e
ComplexitĂ© Ă  long termeÉlevĂ©eMaĂźtrisĂ©e
DéploiementTout ou rienIndépendant
ScalingVerticalHorizontal
TechnologieUniquePolyglotte
ÉquipeUne Ă©quipeÉquipes par service
Base de donnéesPartagéePar service
TransactionsACID simpleSagas (complexe)
DebuggingSimpleDistribué (complexe)
LatenceFaiblePlus élevée
CoĂ»t initialFaibleÉlevĂ©
Time to marketRapide au débutPlus 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:

  1. Service dĂ©marre → s'enregistre auprĂšs d'Eureka
  2. Client veut appeler Service A
  3. Client demande Ă  Eureka: "OĂč est Service A?"
  4. Eureka retourne la liste des instances
  5. Client choisit une instance (load balancing client-side)
  6. 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​

#FacteurDescriptionApplication Spring Boot
1CodebaseUn repo = une appUn repo Git par service
2DependenciesDéclarer explicitementpom.xml / build.gradle
3ConfigConfig dans l'environnementapplication.yml + env vars
4Backing ServicesTraiter comme ressources attachéesDataSource configurable
5Build, Release, RunSéparer les étapesCI/CD pipeline
6ProcessesStatelessSession dans Redis
7Port BindingExporter via portEmbedded Tomcat
8ConcurrencyScale via processusInstances multiples
9DisposabilityDĂ©marrage/arrĂȘt rapideGraceful shutdown
10Dev/Prod ParityEnvironnements similairesDocker
11LogsTraiter comme fluxstdout → collecteur
12Admin ProcessesTĂąches admin one-offSpring 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​

  1. Identifier les Bounded Contexts dans le monolithe
  2. Commencer par le moins risqué (ex: notifications)
  3. Extraire dans un nouveau service
  4. Router via API Gateway
  5. Supprimer l'ancien code du monolithe
  6. 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.


Chapitre Suivant: Service Discovery avec Eureka →

Retour au Module 13