Architecture systèmeArchitecte Système

Formulez un plan architectural pour une plateforme d'orchestration de workflow sans serveur, multi-tenant, capable d'exécuter des millions de processus d'état de longue durée avec des sémantiques exactes, gérant le basculement actif-actif entre régions sans duplication de workflow, et corrélant des événements asynchrones externes avec une latence inférieure à une seconde tout en imposant une stricte isolation des locataires et en maintenant une économie agressive de mise à l'échelle à zéro ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse à la question.

L'architecture est centrée sur le Durable Execution pattern, séparant le calcul éphémère de l'état durable grâce à un plan de contrôle basé sur les événements. Au cœur, les définitions de workflow s'exécutent comme des machines d'état déterministes où chaque transition d'état est persistée en tant qu'événement immuable dans Apache Kafka (journal de pré-écriture) avant l'accusé de réception, permettant une reprise déterministe lors des échecs. La couche de calcul utilise AWS Lambda ou Azure Functions organisées dans des VPC spécifiques aux locataires et des frontières IAM, garantissant l'isolement tout en tirant parti des pools chauds de concurrence provisionnée pour atténuer les démarrages à froid. Pour des sémantiques exactes entre régions, le système utilise CockroachDB avec isolation par défaut sérialisable pour stocker l'état du workflow, utilisant le consensus Raft pour la cohérence inter-régionale sans nécessiter un service de coordinateur séparé. La corrélation d'événements atteint une latence inférieure à une seconde par une approche à plusieurs niveaux : des clusters Redis avec indexation RedisJSON gèrent la correspondance des événements chauds en mémoire, tandis que Elasticsearch sert de stockage à froid pour les requêtes de corrélation historiques, avec Cloudflare Workers fournissant un tampon d'événements côté edge pour absorber les pics de trafic.

Situation de la vie réelle

Lors de Black Friday 2023, SwiftCart (une plateforme de commerce électronique mondiale) a rencontré des échecs catastrophiques dans leur mise en œuvre des Step Functions héritées tout en traitant 50 millions de workflows de livraison concurrents durant chacun 3 à 7 jours. Lorsque us-east-1 a subi une panne régionale, le basculement vers us-west-2 a entraîné 12 000 expéditions dupliquées car la réconciliation de l'état du workflow s'appuyait sur la cohérence éventuelle de DynamoDB avec des fenêtres TTL de 5 minutes. Simultanément, les événements de webhook des transporteurs ont rencontré des retards de corrélation de 30 secondes, rompant les promesses de suivi en temps réel aux clients et entraînant une pénalité de 2 millions de dollars en SLA.

Solution A : Orchestrateur basé sur Kubernetes avec Airflow sur EKS

Cette approche promettait un contrôle total et des outils matures grâce à Apache Airflow fonctionnant sur Amazon EKS avec PostgreSQL comme magasin de métadonnées. Les avantages comprenaient des écosystèmes de plugins étendus et des environnements de développement locaux simples. Cependant, les inconvénients se sont révélés fatals : la latence de planification des pods était en moyenne de 45 secondes, violant l'exigence de mise à l'échelle à zéro selon laquelle les workflows inactifs devaient engendrer des coûts de calcul proches de zéro. De plus, le maintien de la réplication synchrone de PostgreSQL entre les régions ajoutait 200 ms à chaque transition d'état de tâche, et l'absence de sémantiques exactes nécessitait un verrouillage au niveau de l'application complexe qui, pendant les basculements régionaux, était souvent en interblocage.

Solution B : Chorégraphie pure et axée sur les événements utilisant Kafka et Lambda

Cette approche native sans serveur utilisait Amazon MSK (Kafka) comme source de vérité avec des fonctions Lambda réagissant aux événements sans un orchestrateur central. Les avantages comprenaient une vraie économie de paiement à l'utilisation et une résilience naturelle grâce à la persistance basée sur les journaux. Cependant, la mise en œuvre de sémantiques exactes nécessitait des transactions distribuées s'étendant sur DynamoDB (pour l'idempotence) et Kafka, introduisant plus de 500 ms de latence par opération. De plus, la reconstruction de l'état du workflow pour des processus de longue durée (jusqu'au jour 5 d'un workflow de 7 jours) nécessitait de rejouer des millions d'événements à partir des archives S3, entraînant des temps de récupération dépassant 10 minutes et rendant le débogage de "spaghetti distribué" impossible lorsque des échecs survenaient en cours de route.

Solution C : Plateforme d'exécution durable avec gestion d'état partitionné

L'architecture choisie a mis en œuvre un plan de contrôle inspiré de Temporal séparant l'état durable (CockroachDB avec tables géo-partitionnées) des travailleurs éphémères Lambda. Un hashage cohérent répartissait les fragments de workflow sur les nœuds de base de données régionaux, tandis que les flux Redis fournissaient un tampon de corrélation d'événements en sous-millisecondes. Les avantages comprenaient un traitement natif exact grâce aux transactions sérialisées de CockroachDB, une reprise déterministe pour le débogage, et une véritable mise à l'échelle à zéro où les workflows inactifs résidaient uniquement dans des instantanés S3 bon marché. Les inconvénients impliquaient une complexité opérationnelle significative dans le maintien de clusters etcd pour la découverte de services et la nécessité d'un cache sophistiqué pour éviter les charges de troupeau pendant les scénarios de réactivation massifs.

Résultat

En mettant en œuvre la Solution C avec des files d'attente SQS par locataire et des délais de visibilité d'une seconde, SwiftCart a atteint zéro duplication de workflow lors de l'événement Prime Day suivant malgré une panne de 45 minutes dans us-west-2. La latence de corrélation d'événements p95 a chuté à 400 ms grâce au cache edge de Redis. Les coûts d'infrastructure ont diminué de 70 % par rapport à l'approche toujours active d'EKS, avec 85 % des workflows existant uniquement en tant qu'instantanés d'état compressés dans S3 pendant les périodes d'attente inactives, entraînant une économie de 1,4 million de dollars par an.

Ce que les candidats manquent souvent

Comment empêchez-vous la divergence de l'état du workflow lorsque les deux régions traitent simultanément des événements lors d'une partition réseau ?

La plupart des candidats suggèrent incorrectement des sémantiques le dernier écrivant gagne dans DynamoDB ou Cassandra, ce qui échoue pour l'orchestration de workflow car les opérations commerciales ne sont pas commutatives (par exemple, "annuler la commande" par rapport à "expédier la commande" ne peuvent pas être réconciliées uniquement par un horodatage). L'implémentation correcte utilise des horloges vectorielles ou des vecteurs de version pointés intégrés dans les métadonnées de l'état du workflow. Lorsque la partition réseau se rétablit, le système détecte les branches concurrentes grâce à la comparaison des vecteurs de version et applique des fonctions de fusion spécifiques au domaine. Pour les conflits irréconciliables (tels que l'annulation et l'expédition simultanées), l'architecture met en œuvre un motif de compensation de saga où l'opération ultérieure déclenche un retour en arrière de l'action antérieure avec une journalisation d'audit complète. Alternativement, tirer parti de l'isolation sérialisable par défaut de CockroachDB empêche complètement la divergence en rejetant les écritures conflictuelles pendant la partition, forçant des boucles de nouvelle tentative explicites avec un backoff exponentiel plutôt qu'en permettant une corruption silencieuse des données.

Comment gérez-vous la version du code du workflow lorsque qu'un workflow de 7 jours commencé sur v1.0 doit se compléter après que vous ayez déployé v2.0 avec des sémantiques d'activité modifiées ?

Les candidats ignorent souvent la nécessité de la reprise déterministe fondamentale pour l'exécution durable. Mettre à jour simplement le code de la fonction Lambda rompt les workflows en cours car la logique de reprise (utilisée pour reconstruire l'état après des pannes) diverge du chemin d'exécution original, causant des exceptions non déterministes. La solution met en œuvre une version du workflow explicite à travers des marqueurs de sourcing d'événements. Lors du déploiement de v2.0, les travailleurs doivent simultanément prendre en charge les mises en œuvre d'activité v1.0 et v2.0 dans des sandbox WebAssembly ou des sidecars Docker séparés. Les enregistrements d'état du workflow indiquent quelle version de code a exécuté chaque activité historique ; lors de la reprise, le travailleur charge la version historique spécifique de la sandbox pour garantir la réexécution déterministe des étapes passées, tandis que les nouveaux workflows utilisent v2.0. Après la durée maximale du workflow (7 jours plus une marge de sécurité de 24 heures), le code v1.0 peut être décommissionné. Cela nécessite de maintenir des signatures d'activité rétrocompatibles indéfiniment ou d'employer des tests de contrat Pact pour vérifier l'équivalence comportementale entre les versions.

Comment vous protégez-vous contre les workflows de "poison pill" contenant des boucles infinies ou des fuites de mémoire dans le code utilisateur sans rompre les garanties exactes pour les workflows sains ?

De simples Dead Letter Queues (DLQ) violent en fait les sémantiques exactes car le déplacement d'un message vers une DLQ nécessite l'accusé de réception du message d'origine, risquant la perte de message si l'écriture de DLQ échoue ou si le consommateur se bloque au milieu de l'opération. La solution robuste utilise un suivi de progression avec un point de contrôle idempotent. Les travailleurs envoient un heartbeat toutes les 30 secondes, écrivant des jetons de progression sur etcd ou CockroachDB via des opérations de comparaison et d'échange. Si un travailleur échoue trois fois consécutives sur la même tâche de workflow (détectée par un compteur d'essai d'exécution stocké dans la base de données), la tâche est marquée comme "empoisonnée" mais reste dans la file avec un délai de visibilité augmentant de manière exponentielle (1 minute, 5 minutes, 30 minutes). Un pool de travailleurs "chirurgicaux" distinct avec une observabilité améliorée, des limites de mémoire, et un traçage détaillé OpenTelemetry tente ensuite l'exécution. Ce n'est qu'après 24 heures d'échecs persistants que le workflow passe à un état "suspendu" nécessitant l'intervention manuelle de l'opérateur, préservant l'invariance exacte tout au long car toutes les transitions d'état utilisent des timestamps MVCC dans CockroachDB pour des opérations atomiques de comparaison et d'échange.