Défis d'Architecture
Des défis avancés qui combinent plusieurs concepts — conçois des solutions complètes pour des scénarios complexes du monde réel.
Objectif
Les défis de cette section combinent plusieurs concepts d’architecture dans des scénarios complexes. Contrairement aux laboratoires précédents (qui se concentrent sur un seul sujet), tu devras ici intégrer des patterns, de la résilience, de la sécurité et des opérations dans des solutions complètes.
Chaque défi possède un niveau de difficulté et une durée estimée. Essaie de les résoudre avant de consulter les indices.
Défi 1 : Migration sans interruption de service
Niveau : Intermédiaire | Durée estimée : 30-45 minutes
Scénario
Ton entreprise possède un monolithe qui gère l’authentification, le catalogue et les commandes. Tu dois extraire le service de commandes sous forme de microservice sans interruption de service. Le monolithe traite 500 commandes par heure et ne peut pas être arrêté.
Exigences
- Zéro interruption de service pendant la migration
- Capacité de rollback à tout moment
- Les données historiques des commandes doivent être disponibles dans le nouveau service
- Les rapports existants doivent continuer à fonctionner
Ta mission
Conçois un plan de migration étape par étape. Prends en compte :
- Comment migrer les données sans arrêter le monolithe ?
- Comment rediriger le trafic progressivement ?
- Comment vérifier que le nouveau service fonctionne correctement ?
- Quel est ton plan de rollback ?
Indices
Indice 1 : Pattern de migration
Utilise le pattern Strangler Fig :
- Crée le nouveau service de commandes
- Redirige d’abord les lectures (moins de risque)
- Redirige ensuite les écritures
- Enfin, supprime le code des commandes du monolithe
Indice 2 : Migration des données
Utilise le Change Data Capture (CDC) :
- Fais un dump initial des commandes historiques vers le nouveau service
- Configure le CDC pour répliquer les changements en temps réel du monolithe vers le nouveau service
- Lorsque les deux sont synchronisés, redirige le trafic
Indice 3 : Vérification
Utilise le pattern Shadow Traffic :
- Envoie une copie de chaque requête au nouveau service (sans impacter l’utilisateur)
- Compare les réponses du monolithe et du nouveau service
- Lorsque les réponses coïncident à 99,9 %, redirige le trafic réel
Solution de référence
Voir la solution complète
Phase 1 — Préparation (semaine 1-2) :
- Créer le nouveau service de commandes avec la même API
- Configurer le CDC depuis la table des commandes du monolithe
- Migrer les données historiques avec un script batch
Phase 2 — Vérification (semaine 3) :
- Activer le shadow traffic : chaque requête vers le monolithe est dupliquée vers le nouveau service
- Comparer automatiquement les réponses et enregistrer les divergences
- Corriger les bugs jusqu’à ce que les réponses coïncident
Phase 3 — Migration progressive (semaine 4) :
- Rediriger 10 % du trafic de lecture vers le nouveau service
- Surveiller la latence, les erreurs et la cohérence des données
- Augmenter progressivement : 25 % → 50 % → 75 % → 100 %
Phase 4 — Écritures (semaine 5) :
- Rediriger les écritures vers le nouveau service
- Le nouveau service publie des événements que le monolithe consomme (pour les rapports legacy)
- Surveiller intensivement pendant 48 heures
Phase 5 — Nettoyage (semaine 6) :
- Supprimer le code des commandes du monolithe
- Désactiver le CDC
- Mettre à jour les rapports pour utiliser la nouvelle source de données
Rollback à n’importe quelle phase : Rétablir la configuration du proxy/load balancer pour envoyer le trafic vers le monolithe.
Défi 2 : Système de paiement multi-fournisseur
Niveau : Avancé | Durée estimée : 45-60 minutes
Scénario
Conçois un service de paiement qui prend en charge plusieurs fournisseurs (Stripe, PayPal, virement bancaire) avec les exigences suivantes :
- Idempotence : un paiement ne peut pas être traité deux fois
- Résilience : si un fournisseur échoue, essayer automatiquement avec un autre
- Audit : chaque tentative de paiement doit être enregistrée
- Réconciliation : pouvoir vérifier que les débits correspondent aux commandes
- PCI compliance : ne pas stocker de données de carte dans ton système
Ta mission
Conçois :
- L’API du service de paiement
- Le flux interne de traitement
- Le modèle de données
- Les stratégies de résilience
- Le flux de réconciliation
Indices
Indice 1 : Idempotence
Utilise une idempotency key générée par le client :
POST /payments
Headers: Idempotency-Key: uuid-unique-per-payment
Body: { orderId, amount, currency, provider }
Avant de traiter, vérifie s’il existe déjà un paiement avec cette clé. S’il existe, retourne le résultat précédent sans le traiter à nouveau.
Indice 2 : Modèle de données
Payment {
id: UUID
idempotencyKey: string (unique)
orderId: string
amount: decimal
currency: string
status: PENDING | PROCESSING | COMPLETED | FAILED | REFUNDED
provider: STRIPE | PAYPAL | BANK_TRANSFER
providerTransactionId: string?
attempts: PaymentAttempt[]
createdAt: timestamp
updatedAt: timestamp
}
PaymentAttempt {
id: UUID
paymentId: UUID
provider: string
status: SUCCESS | FAILED | TIMEOUT
errorCode: string?
errorMessage: string?
responseTime: number
attemptedAt: timestamp
}
Indice 3 : Stratégie de fallback
Définis un ordre de priorité des fournisseurs par type de paiement :
- Carte de crédit : Stripe → PayPal
- Carte de débit : Stripe → PayPal
- Virement : uniquement banque
Si le fournisseur principal échoue avec une erreur récupérable (timeout, 503), essayer avec le suivant. S’il échoue avec une erreur non récupérable (carte refusée, fonds insuffisants), ne pas réessayer.
Défi 3 : Conçois un système de notifications
Niveau : Intermédiaire | Durée estimée : 30-45 minutes
Scénario
Conçois un service de notifications qui prend en charge :
- Canaux : email, push, SMS, in-app
- Priorités : critique (immédiate), haute (< 1 min), normale (< 5 min), basse (batch quotidien)
- Préférences : les utilisateurs peuvent choisir quels canaux recevoir par type de notification
- Rate limiting : ne pas envoyer plus de 10 notifications par heure par utilisateur
- Templates : les notifications utilisent des templates avec des variables dynamiques
Ta mission
- Définis l’API pour envoyer des notifications
- Conçois le flux de traitement interne
- Définis comment tu gères les préférences de l’utilisateur
- Conçois la stratégie de rate limiting
- Définis ce qui se passe lorsqu’un canal échoue
Considérations
- Utilises-tu une file par priorité ou une file avec priorités ?
- Comment gères-tu le batch quotidien des notifications de basse priorité ?
- Que se passe-t-il si le service d’email est en panne mais que celui de push fonctionne ?
- Comment évites-tu d’envoyer deux fois la même notification ?
Voir l'architecture suggérée
[API de Notifications]
│
▼
[File de priorité]
├── File CRITICAL (traitement immédiat, workers dédiés)
├── File HIGH (traitement < 1 min)
├── File NORMAL (traitement < 5 min)
└── File LOW (accumulation pour batch)
│
▼
[Notification Processor]
│
├── Vérifier les préférences de l'utilisateur
├── Appliquer le rate limiting
├── Résoudre le template avec les variables
│
▼
[Channel Router]
├──► [Email Provider] (SendGrid/SES)
├──► [Push Provider] (Firebase/APNs)
├──► [SMS Provider] (Twilio)
└──► [In-App Store] (WebSocket/DB)
Rate limiting : Utiliser Redis avec un compteur par utilisateur avec un TTL de 1 heure. Avant d’envoyer, vérifier le compteur. Si la limite est dépassée, mettre en file d’attente pour la période suivante.
Déduplication : Utiliser une clé composée (userId + notificationType + entityId) avec un TTL pour éviter les doublons.
Défi 4 : Observabilité end-to-end
Niveau : Avancé | Durée estimée : 45-60 minutes
Scénario
Tu as 8 microservices en production. Un utilisateur signale que « parfois le checkout prend beaucoup de temps ». Tu n’arrives pas à reproduire le problème de manière consistante. Conçois une stratégie d’observabilité qui te permette de diagnostiquer ce type de problèmes.
Ta mission
- Quelles métriques collecterais-tu de chaque service ?
- Comment implémenterais-tu le distributed tracing ?
- Quelles alertes configurerais-tu ?
- Comment corrélerais-tu les logs entre les services ?
- Quel dashboard créerais-tu pour l’équipe de garde ?
Critères de réussite
Ta conception doit permettre :
- D’identifier quel service provoque la latence en moins de 5 minutes
- De voir le trace complet d’une requête de l’utilisateur
- De détecter les dégradations avant que les utilisateurs ne les signalent
- De comprendre l’impact d’un deploy sur la latence du système
Voir la stratégie suggérée
Métriques (par service) :
- Latence : p50, p90, p95, p99 par endpoint
- Taux d’erreurs : 4xx et 5xx par endpoint
- Throughput : requêtes par seconde
- Saturation : CPU, mémoire, connexions de DB, pool de threads
Distributed tracing :
- Générer un
traceIddans l’API Gateway - Le propager via le header
X-Trace-Idà tous les services - Chaque service enregistre des spans avec début, fin et metadata
- Utiliser OpenTelemetry comme standard
Alertes :
- Latence p99 > 2x du baseline pendant plus de 5 minutes
- Taux d’erreurs 5xx > 1 % pendant plus de 2 minutes
- File de messages qui grandit pendant plus de 10 minutes
- CPU > 80 % pendant plus de 5 minutes
Dashboard de garde :
- Vue générale : health de tous les services (vert/jaune/rouge)
- Vue de flux : latence par étape du checkout
- Vue des traces : les 10 traces les plus lents de la dernière heure
- Vue des erreurs : erreurs regroupées par type et par service
Réflexion
Après avoir complété les défis :
- Quel a été le défi le plus difficile ? Pourquoi ?
- Dans quels domaines sens-tu que tu as besoin de plus de pratique ?
- As-tu pu réutiliser des patterns des sections précédentes ?
- Quel défi ressemble le plus à un problème réel que tu rencontres dans ton travail ?
Les défis sont conçus pour simuler la complexité réelle de l’architecture logicielle. Il n’y a pas de solutions parfaites — il y a des solutions bien raisonnées.