Questions d'entretien Microservices
Les entretiens sur les microservices évaluent votre capacité à concevoir et construire des systèmes évolutifs et décentralisés. Ils ciblent souvent les ingénieurs seniors et les architectes ayant une connaissance approfondie du calcul distribué, des API et de la cohérence des données. Attendez-vous à un mélange de discussions architecturales, d'analyses de compromis et de scénarios de codage pratiques.
Ce que couvrent les entretiens Microservices
Décomposition et conception de services
Comment diviser un monolithe en services, contextes délimités et principes de conception pilotée par le domaine.
Communication inter-services
Motifs synchrones vs asynchrones, passerelles API, service mesh et protocoles de communication.
Gestion des données et cohérence
Gestion des transactions distribuées, cohérence éventuelle, sagas et CQRS/event sourcing.
Déploiement et observabilité
Conteneurisation, orchestration (Kubernetes), surveillance, journalisation et traçage dans les systèmes distribués.
Exemples de questions d'entretien Microservices
- Comment décomposeriez-vous un grand monolithe en microservices ? Parcourez votre processus de décision.Ce qu'une bonne réponse couvre
- Identifier les bounded contexts du domaine
- Analyser les dépendances et les couplages
- Extraire les services par fonctionnalité métier
- Gérer les données partagées et les transactions
- Planifier une extraction incrémentale avec strangler fig pattern
Voir un exemple de réponse
La décomposition d'un monolithe en microservices commence par l'identification des bounded contexts selon le Domain-Driven Design. On analyse les dépendances entre les modules pour trouver les couplages forts et faibles. On extrait d'abord les services avec des frontières métier claires, souvent autour d'agrégats ou de flux de valeur. Il faut gérer les données partagées en les divisant par service, avec des API pour l'accès. On utilise le pattern strangler fig pour migrer progressivement les fonctionnalités. Un piège courant est de couper trop tôt les transactions ACID : il faut accepter la cohérence éventuelle et introduire des événements ou sagas. La surveillance des performances et des erreurs est cruciale pendant la transition. On doit aussi prévoir des tests d'intégration pour valider les interfaces entre services.
- Expliquez la différence entre orchestration et chorégraphie dans les motifs saga. Quand utiliseriez-vous chacun ?Ce qu'une bonne réponse couvre
- Orchestration : un coordinateur central gère la logique de la saga
- Chorégraphie : chaque service réagit aux événements des autres
- Complexité vs couplage : orchestration centralise la logique, chorégraphie distribue
- Choix basé sur la taille et la criticité du workflow
Voir un exemple de réponse
Dans le motif saga, l'orchestration utilise un orchestrateur qui ordonne et appelle chaque étape, gérant les compensations en cas d'échec. C'est plus simple à comprendre et à déboguer, mais crée un point central de défaillance et un couplage fort avec l'orchestrateur. La chorégraphie repose sur des événements asynchrones : chaque service publie des événements et écoute ceux des autres, ce qui réduit le couplage mais augmente la complexité de suivi et de gestion des échecs. On choisit l'orchestration pour les workflows critiques où le contrôle central est nécessaire, ou quand la logique de compensation est complexe. La chorégraphie convient aux workflows simples ou très dynamiques, où les services doivent être indépendants. Par exemple, un système de commande peut utiliser l'orchestration pour la validation de paiement, mais la chorégraphie pour la mise à jour du stock après expédition.
- Écrivez une implémentation simple de circuit breaker dans votre langage préféré (pseudo-code accepté).Ce qu'une bonne réponse couvre
- Trois états : fermé, ouvert, semi-ouvert
- Compteur d'échecs et seuil pour ouvrir le circuit
- Timeout et tentative de réessai en semi-ouvert
- Implémentation simple avec un compteur et un minuteur
Voir un exemple de réponse
L'implémentation ci-dessus montre un circuit breaker avec trois états. En état fermé, les appels passent normalement mais on compte les échecs ; si le seuil est atteint, le circuit s'ouvre. En état ouvert, les appels sont rejetés immédiatement jusqu'à un timeout. Après le timeout, on passe en semi-ouvert pour tester si le service est rétabli. Un seul échec en semi-ouvert le referme en open. Cette implémentation simple omet des fonctionnalités avancées comme la gestion des délais d'attente, les exceptions spécifiques, ou le half-open success threshold. En production, on utiliserait des bibliothèques comme Hystrix ou Resilience4j. Le pattern améliore la résilience en évitant les appels répétés à un service défaillant.
Solution de référencepython import time class CircuitBreaker: def __init__(self, threshold=5, recovery_timeout=30): self.threshold = threshold self.recovery_timeout = recovery_timeout self.failure_count = 0 self.state = 'CLOSED' self.last_failure_time = None def call(self, func, *args, **kwargs): if self.state == 'OPEN': if time.time() - self.last_failure_time >= self.recovery_timeout: self.state = 'HALF_OPEN' else: raise Exception('Circuit breaker is open') try: result = func(*args, **kwargs) if self.state == 'HALF_OPEN': self.state = 'CLOSED' self.failure_count = 0 return result except Exception as e: self.failure_count += 1 self.last_failure_time = time.time() if self.failure_count >= self.threshold: self.state = 'OPEN' raise e # Exemple d'utilisation breaker = CircuitBreaker(threshold=3, recovery_timeout=10) def risque(): # fonction qui peut échouer pass - Comment gérez-vous les transactions distribuées avec cohérence éventuelle ? Fournissez un exemple concret.Ce qu'une bonne réponse couvre
- Utiliser des sagas avec orchestration ou chorégraphie
- Appliquer le pattern 'Event Sourcing' pour conserver l'état
- Compenser les échecs via des transactions compensatoires
- Accepter la cohérence éventuelle avec des mécanismes de rapprochement
Voir un exemple de réponse
Pour les transactions distribuées avec cohérence éventuelle, on utilise le motif saga qui décompose la transaction en étapes locales avec des actions compensatoires. Par exemple, dans un système de réservation de voyage, une saga peut inclure la réservation d'un vol et d'un hôtel. Si la réservation d'hôtel échoue après la réservation de vol, on annule la réservation de vol (compensation). On peut implémenter cela avec orchestration (un coordinateur) ou chorégraphie (événements). L'Event Sourcing permet de reconstruire l'état et de retracer les événements pour le debugging. Un exemple concret : lors d'une commande, on débite la carte, puis on met à jour le stock ; si le stock est insuffisant, on crédite la carte. On doit aussi prévoir des jobs de rapprochement pour détecter les incohérences. La clé est de concevoir des compensations idempotentes et de gérer les échecs en cascade.
- Concevez une passerelle API pour un système avec 10+ microservices. Quelles fonctionnalités inclurait-elle ?Ce qu'une bonne réponse couvre
- Routage vers les services appropriés
- Authentification et autorisation centralisées
- Limitation de débit et gestion des quotas
- Transformation de protocoles et agrégation de réponses
- Monitoring, logging et cache
Voir un exemple de réponse
Une passerelle API pour 10+ microservices doit d'abord offrir le routage intelligent basé sur le chemin d'URL ou les en-têtes. Elle centralise l'authentification (JWT, OAuth2) et l'autorisation, évitant la duplication. La limitation de débit (rate limiting) protège les services avals. La transformation de protocoles (par exemple, HTTP à gRPC) et l'agrégation de réponses de plusieurs services en une seule réponse réduisent le nombre d'appels clients. Elle doit inclure la mise en cache côté passerelle pour les requêtes fréquentes. Le monitoring avec des métriques (latence, erreurs) et le logging structuré sont essentiels. Enfin, on peut ajouter un circuit breaker pour les appels sortants et une fonction de découverte de services. Attention à ne pas surcharger la passerelle de logique métier, elle doit rester légère et scalable horizontalement.
- Décrivez un scénario où vous choisiriez gRPC plutôt que REST pour la communication inter-services.Ce qu'une bonne réponse couvre
- gRPC est performant avec HTTP/2 et Protobuf
- Contrats forts avec définition .proto
- Support du streaming bidirectionnel
- Microservices internes avec faible latence
Voir un exemple de réponse
Je choisirais gRPC plutôt que REST dans un scénario où les microservices communiquent à fort volume et exigent une faible latence. Par exemple, dans un système de recommandation en temps réel où des centaines de requêtes par seconde transitent entre services. gRPC utilise HTTP/2 et la sérialisation binaire Protobuf, ce qui réduit la taille des messages et améliore les performances. De plus, son contrat fort via les fichiers .proto permet de générer automatiquement des stubs clients et serveurs, réduisant les erreurs d'interface. Le streaming bidirectionnel est utile pour des applications comme les chats ou les flux d'événements. En revanche, REST reste préférable pour des API exposées à l'extérieur ou quand on a besoin de flexibilité et de compatibilité avec des navigateurs. gRPC est donc idéal pour la communication interne entre microservices dans un écosystème contrôlé.
- Comment implémenteriez-vous le traçage distribué entre microservices ? Quels outils utiliseriez-vous ?Ce qu'une bonne réponse couvre
- Assigner un identifiant de trace unique à chaque requête
- Propager le contexte via les en-têtes HTTP ou métadonnées
- Instrumenter chaque service pour émettre des spans
- Utiliser OpenTelemetry pour la collecte et Jaeger ou Zipkin pour la visualisation
Voir un exemple de réponse
Le traçage distribué consiste à attribuer un ID de trace à la requête entrante et à propager ce contexte à chaque appel inter-service. On utilise généralement les en-têtes comme 'traceparent' (W3C Trace Context) pour passer la trace ID et le span ID. Chaque service crée des spans représentant les unités de travail, avec des horodatages et des métadonnées. OpenTelemetry est la norme pour instrumenter les applications, collecter les traces et les exporter vers des backend comme Jaeger ou Zipkin. Ces outils permettent de visualiser les flux de requêtes et d'identifier les goulots d'étranglement ou les échecs. Il est important de s'assurer que la propagation de contexte ne soit pas interrompue par des files d'attente ou des messages asynchrones. On peut aussi ajouter des attributs personnalisés pour enrichir le traçage. Enfin, le coût d'instrumentation doit être surveillé pour ne pas impacter les performances.
- Codez un point de terminaison de vérification de santé qui rapporte l'état des dépendances aval (par exemple, base de données, cache, autres services).Ce qu'une bonne réponse couvre
- Endpoint GET /health renvoyant l'état global
- Interroger chaque dépendance (DB, cache, services) avec timeout court
- Agréger les résultats avec un statut UP/DOWN/DEGRADED
- Inclure des informations de latence et de version
Voir un exemple de réponse
L'endpoint de vérification de santé doit interroger chaque dépendance avec un timeout court pour éviter de bloquer. La fonction check_database tente une connexion et retourne UP/DOWN. De même pour le cache Redis. Pour les autres services, on appelle leur endpoint /health et on capture la latence. On agrège les résultats et on définit le statut global : UP si tout va bien, DEGRADED si un service non critique est en panne, DOWN si critique. Il est important d'exclure les dépendances optionnelles du statut global. On inclut aussi des métadonnées comme la version du service ou la mémoire utilisée. Attention à ne pas cascader les appels : un service aval peut être en panne et ralentir le health check. On peut utiliser une approche asynchrone ou un circuit breaker. Cet endpoint est utilisé par les orchestrateurs (Kubernetes) pour les liveness et readiness probes.
Solution de référencepython from flask import Flask, jsonify import requests import redis import psycopg2 app = Flask(__name__) def check_database(): try: conn = psycopg2.connect(host='localhost', dbname='test', user='user', password='pass', connect_timeout=2) conn.close() return {'status': 'UP'} except Exception as e: return {'status': 'DOWN', 'error': str(e)} def check_cache(): try: r = redis.Redis(host='localhost', port=6379, socket_connect_timeout=2) r.ping() return {'status': 'UP'} except Exception as e: return {'status': 'DOWN', 'error': str(e)} def check_service(service_url): try: resp = requests.get(f'{service_url}/health', timeout=2) if resp.status_code == 200: return {'status': 'UP', 'latency': resp.elapsed.total_seconds()} else: return {'status': 'DEGRADED', 'http_status': resp.status_code} except Exception as e: return {'status': 'DOWN', 'error': str(e)} @app.route('/health') def health(): health_status = { 'status': 'UP', 'database': check_database(), 'cache': check_cache(), 'service_a': check_service('http://service-a:5000/health') } if any(dep['status'] != 'UP' for dep in health_status.values() if isinstance(dep, dict)): health_status['status'] = 'DEGRADED' return jsonify(health_status) if __name__ == '__main__': app.run(port=5000)
Comment se préparer
- Maîtrisez les fondamentaux des systèmes distribués : théorème CAP, modèles de cohérence et tolérance aux pannes.
- Entraînez-vous à la décomposition de services en utilisant la conception pilotée par le domaine (entités, agrégats, contextes délimités).
- Comprenez la cohérence éventuelle et comment implémenter les motifs saga (par exemple, avec des transactions de compensation).
- Soyez prêt à discuter des compromis : orchestration vs chorégraphie, synchrone vs asynchrone, avec état vs sans état.
- Préparez-vous aux problèmes de conception de systèmes : entraînez-vous à dessiner une architecture microservices au tableau blanc en vous concentrant sur la communication, les données et l'observabilité.
Questions fréquemment posées
Quels sont les concepts les plus importants pour un entretien sur les microservices ?
Les concepts clés incluent la décomposition de services, la communication inter-services (REST, gRPC, messagerie), la cohérence des données (sagas, cohérence éventuelle) et l'observabilité (journalisation, métriques, traces).
Dois-je connaître Kubernetes pour les entretiens sur les microservices ?
Oui, Kubernetes est souvent utilisé pour orchestrer les conteneurs. Vous devez comprendre les pods, services, déploiements et comment gérer les microservices dans un cluster.
En quoi les entretiens sur les microservices diffèrent-ils des entretiens généraux de conception de systèmes ?
Les entretiens sur les microservices se concentrent spécifiquement sur les défis d'architecture distribuée comme les limites de services, la distribution des données et la résilience réseau, tandis que la conception de systèmes générale peut également couvrir les monolithes.
À quelles questions de codage puis-je m'attendre dans un entretien sur les microservices ?
On peut vous demander d'implémenter un circuit breaker, un mécanisme de tentative, ou un simple point de terminaison de santé de service. Aussi, vous pourriez avoir besoin de concevoir une API ou d'écrire du code pour la communication inter-services.
Comment puis-je démontrer mon expérience avec les microservices si je n'ai pas travaillé avec eux en production ?
Construisez un petit projet en utilisant des motifs de microservices (par exemple, avec Docker, Node.js/Spring Boot et une file de messages). Discutez des compromis et des leçons apprises. Les connaissances théoriques combinées à un projet personnel peuvent être convaincantes.
Pratiquez les questions Microservices avec des retours instantanés de l'IA
Téléchargez votre CV, obtenez un entretien simulé personnalisé et voyez exactement ce qu'il faut améliorer — gratuit pour commencer.