Créez des pipelines de streaming avec état qui suivent des millions de sessions d'appareils de jeu actives, produisant des heartbeats en temps réel avec une latence inférieure à la seconde dans Apache Spark
par Neha Prabhu et Murali Talluri
Dans le secteur des jeux vidéo, chaque milliseconde compte. Pour piloter la personnalisation en jeu, alimenter les moteurs de recommandation et prendre des décisions de planification dynamique du contenu, les plateformes doivent traiter les données de session de millions de joueurs dans le monde avec une latence inférieure à la seconde.
Aujourd'hui, répondre à ces exigences de latence ultra-faible ne nécessite plus une architecture décousue avec plusieurs moteurs. Dans ce blog, nous explorons une implémentation concrète d' Apache Spark Real-Time Mode. En exploitant le nouvel opérateur transformWithState pour une logique avec état complexe, nous démontrons comment Spark offre des performances de l'ordre de la milliseconde de bout en bout. Découvrez comment votre équipe peut accélérer le développement et concevoir des applications opérationnelles critiques en utilisant l'écosystème familier de Structured Streaming.
Pour les plateformes de jeux, savoir quels appareils sont actifs et pendant combien de temps n'est pas seulement une préoccupation d'infrastructure : cela stimule l'activité commerciale. Les données de session en temps réel alimentent des expériences personnalisées en jeu, soutiennent les moteurs de recommandation, éclairent les décisions de planification du contenu et fournissent des signaux sur l'état des appareils pour des millions de consoles et de PC. Les équipes opérationnelles les utilisent pour appliquer le contrôle parental et détecter des modèles de session anormaux.
Les événements de session provenant des consoles et des PC sont acheminés vers des topics Kafka. Chaque événement comporte un ID d'appareil et un ID de session. L'ID d'appareil identifie la console ou le PC ; l'ID de session identifie la session de jeu. Une seule session peut être active par appareil à la fois.
Le pipeline gère quatre scénarios :
Spark Structured Streaming en mode micro-batch peut gérer la sessionisation avec état, mais lorsque le cas d'usage exige une précision inférieure à la seconde pour le traitement des entrées et les sorties déclenchées par minuteur, le mode micro-batch montre ses limites. Par le passé, cette lacune poussait les équipes à gérer un moteur spécialisé supplémentaire ou à concevoir des solutions sur mesure.
Avec Apache Flink : la gestion de l'état et les minuteurs peuvent être implémentés, mais adopter Flink signifie adopter tout un écosystème parallèle : un cluster distinct, un backend d'état, un modèle de déploiement, une pile de surveillance et une base de code, le tout aux côtés de la plateforme Databricks. Il en résulte une fragmentation de l'infrastructure, une complexité opérationnelle et le coût d'exploitation et de dotation en personnel d'un second moteur de streaming.
Avec des solutions internes sur mesure : certaines équipes conçoivent leur propre service de sessionisation, par exemple un système d'acteurs basé sur Akka où chaque appareil dispose d'un acteur qui gère l'état de la session, les minuteurs et l'émission de heartbeats. Ces solutions entraînent la même surcharge infrastructurelle et opérationnelle que Flink, avec un défi supplémentaire : elles ne passent pas à l'échelle. Distribuer des millions d'acteurs avec état sur plusieurs nœuds est une tâche que vous devez concevoir vous-même. Ces systèmes fonctionnent au départ, mais finissent avec le temps en mode maintenance : assez stables pour fonctionner, mais difficiles à faire évoluer.
Aujourd'hui, le Real-Time Mode comble cette lacune pour les clients, en offrant une précision inférieure à la seconde avec les mêmes API Spark que les équipes utilisent déjà, le tout dans un seul moteur unifié.
transformWithState est un opérateur de nouvelle génération dans Spark Structured Streaming qui rend le traitement avec état complexe flexible et évolutif. Les fonctionnalités clés incluent la gestion d'état orientée objet, les types de données composites, la logique pilotée par minuteur, la prise en charge automatique du TTL et l'évolution des schémas. Associé au Real-Time Mode, il offre une précision inférieure à la seconde pour le traitement des entrées et les sorties déclenchées par minuteur.
Le cas d'usage de la sessionisation de jeu exige deux choses :
transformWithState offre ces deux fonctionnalités dans une seule classe StatefulProcessor avec deux méthodes dédiées.
handleInputRows() réagit aux événements Kafka entrants, en traitant les débuts et fins de session et en maintenant l'état de sessionisation au fur et à mesure de l'arrivée des événements.
handleExpiredTimer() gère tout ce qui se passe entre-temps, en se déclenchant pour produire des sorties proactives telles que des heartbeats et des expirations, que de nouvelles données soient arrivées ou non.

Pour une présentation détaillée de l'architecture, de l'implémentation du code et des considérations de production, consultez ce blog complémentaire , où nous détaillons le code de StatefulProcessor, le cycle de vie des minuteurs, les modèles de gestion d'état et la surveillance avec StreamingQueryListener. Les résultats suivants illustrent les caractéristiques de débit et de latence du pipeline, mettant en évidence les différences de latence significatives entre le mode micro-batch (MBM) et le Real-Time Mode (RTM) :
Pour valider le pipeline sous une charge réaliste, nous l'avons testé avec le débit soutenu suivant :
Métrique (par minute) | Valeur |
Événements d'entrée (débuts + fins de session) | ~500 k |
Nombre de sessions actives | ~4 M |
Enregistrements de heartbeat émis | ~8 M |
Amplification entrée-sortie | ~16x |
La grande majorité des sorties n'est pas déclenchée par les données entrantes : elle est entièrement générée par handleExpiredTimer(), qui émet de manière proactive des heartbeats selon un calendrier planifié.
La latence est mesurée de bout en bout, de l'horodatage du topic Kafka d'entrée à l'horodatage du topic de sortie. Avec le Real-Time Mode, le pipeline atteint une latence p99 de 432 ms, soit 20 fois plus rapide que le mode micro-batch.

Les cas d'usage comme la sessionisation de jeux nécessitent des pipelines qui vont au-delà du traitement des événements entrants — émission proactive de heartbeats de manière planifiée, suivi de millions de sessions simultanées et gestion efficace de l'état. Ce modèle ne se limite pas aux jeux. Tout cas de charge nécessitant des sorties déclenchées par timer — heartbeats IoT, suivi de sessions, alertes en temps réel, surveillance d'équipements — peut être conçu de la même manière.
Les timers dans transformWithState rendent cela possible. Une seule classe StatefulProcessor gère l'intégralité du cycle de vie de la session — le traitement réactif des entrées et la génération proactive de sorties déclenchées par timer. Associé au Real-Time Mode, les enregistrements d'entrée sont traités et les timers se déclenchent avec une précision inférieure à la seconde — pas lors du prochain intervalle de micro-lot (micro-batch), mais immédiatement. Le tout au sein de Databricks, sans moteur secondaire.
Si vous exécutez déjà des pipelines Structured Streaming en mode micro-batch et que vous envisagez un second moteur pour obtenir une latence plus faible, essayez d'abord le Real-Time Mode. Le passage de l'un à l'autre se fait par un simple changement de déclencheur (trigger) — pas de réécriture, pas de changement de plateforme :
Essayez par vous-même :
Le Real-Time Mode est désormais en disponibilité générale.
(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original
Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.