Crie pipelines de streaming com estado que rastreiam milhões de sessões de dispositivos de jogos ativos, gerando heartbeats em tempo real com latência de subsegundos no Apache Spark
por Neha Prabhu e Murali Talluri
No setor de jogos, cada milissegundo conta. Para impulsionar a personalização no jogo, alimentar mecanismos de recomendação e tomar decisões dinâmicas de agendamento de conteúdo, as plataformas precisam processar dados de sessão de milhões de jogadores em todo o mundo com latência abaixo de um segundo.
Hoje, atender a esses requisitos de latência ultrabaixa não exige mais uma arquitetura fragmentada com vários mecanismos. Neste blog, exploramos uma implementação real do Apache Spark Real-Time Mode. Ao aproveitar o novo operador transformWithState para lógica de estado complexa, demonstramos como o Spark oferece desempenho de milissegundos de ponta a ponta. Descubra como sua equipe pode acelerar o desenvolvimento e criar aplicativos operacionais de missão crítica usando o ecossistema familiar do Structured Streaming.
Para plataformas de jogos, saber quais dispositivos estão ativos e por quanto tempo não é apenas uma preocupação de infraestrutura — isso impulsiona os negócios. Os dados de sessão em tempo real alimentam experiências personalizadas no jogo, motores de recomendação, decisões de agendamento de conteúdo e fornecem sinais de integridade do dispositivo em milhões de consoles e PCs. As equipes de operações os utilizam para aplicar controles parentais e detectar padrões de sessão anômalos.
Os eventos de sessão de consoles e PCs fluem para tópicos do Kafka. Cada evento carrega um ID de dispositivo e um ID de sessão. O ID do dispositivo identifica o console ou PC; o ID da sessão identifica a sessão de jogo. Apenas uma sessão pode estar ativa por dispositivo a qualquer momento.
O pipeline lida com quatro cenários:
O Spark Structured Streaming no modo micro-batch pode lidar com a sessionalização com estado, mas quando o caso de uso exige precisão abaixo de um segundo tanto para o processamento de entrada quanto para a saída orientada por timer, o micro-batch deixa a desejar. No passado, essa lacuna levava as equipes a gerenciar mecanismos especializados adicionais ou a criar soluções personalizadas.
Com o Apache Flink: o gerenciamento de estado e os timers podem ser implementados, mas adotar o Flink significa adotar todo um ecossistema paralelo: um cluster separado, back-end de estado, modelo de implantação, pilha de monitoramento e base de código, tudo junto com a plataforma Databricks. O resultado é a fragmentação da infraestrutura, complexidade operacional e o custo de operar e manter uma equipe para um segundo mecanismo de streaming.
Com soluções internas personalizadas: algumas equipes criam seu próprio serviço de sessionalização — por exemplo, um sistema de atores baseado em Akka onde cada dispositivo recebe um ator que gerencia o estado da sessão, timers e emissão de heartbeat. Eles trazem a mesma sobrecarga operacional e de infraestrutura do Flink, com um desafio adicional: não escalam. Distribuir milhões de atores com estado entre nós é algo que você mesmo precisa desenvolver. Esses sistemas funcionam inicialmente, mas com o tempo acabam em modo de manutenção — estáveis o suficiente para rodar, mas difíceis de estender.
Hoje, o Real-Time Mode elimina essa lacuna para os clientes — oferecendo precisão abaixo de um segundo com as mesmas APIs do Spark que as equipes já usam, tudo em um único mecanismo unificado.
transformWithState é um operador de última geração no Spark Structured Streaming que torna o processamento com estado complexo flexível e escalável. Os principais recursos incluem gerenciamento de estado orientado a objetos, tipos de dados compostos, lógica orientada por timer, suporte automático a TTL e evolução de esquema. Combinado com o Real-Time Mode, ele oferece precisão abaixo de um segundo tanto para o processamento de entrada quanto para a saída orientada por timer.
O caso de uso de sessionalização de jogos exige duas coisas:
transformWithState oferece ambos em uma única classe StatefulProcessor com dois métodos dedicados.
O handleInputRows() reage aos eventos recebidos do Kafka — processando o início e o fim das sessões, mantendo o estado de sessionalização à medida que os eventos chegam.
O handleExpiredTimer() lida com tudo o que acontece no intervalo — sendo acionado para produzir saídas proativas, como heartbeats e timeouts, independentemente de novos dados terem chegado ou não.

Para uma análise detalhada da arquitetura, implementação do código e considerações de produção, consulte este blog complementar — onde detalhamos o código do StatefulProcessor, o ciclo de vida do timer, os padrões de gerenciamento de estado e o monitoramento com o StreamingQueryListener. Os resultados a seguir ilustram as características de taxa de transferência e latência do pipeline, destacando as diferenças significativas de latência entre o modo micro-batch (MBM) e o Real-Time Mode (RTM):
Para validar o pipeline sob uma carga realista, testamos com a seguinte taxa de transferência sustentada:
Métrica (por minuto) | Valor |
Eventos de entrada (inícios + fins de sessão) | ~500K |
Número de sessões ativas | ~4M |
Registros de heartbeat emitidos | ~8M |
Amplificação de entrada para saída | ~16x |
A grande maioria das saídas não é acionada por dados de entrada — ela é gerada inteiramente pelo handleExpiredTimer(), emitindo heartbeats proativamente em um cronograma.
A latência é medida de ponta a ponta — do timestamp do tópico de entrada do Kafka ao timestamp do tópico de saída. Com o Real-Time Mode, o pipeline atinge uma latência p99 de 432 ms — 20 vezes mais rápido que o modo micro-batch.

Casos de uso como a sessionalização de jogos exigem pipelines que vão além do processamento de eventos recebidos — emitindo heartbeats proativamente em um cronograma, rastreando milhões de sessões simultâneas e gerenciando o estado de forma eficiente. O padrão não se limita a jogos. Qualquer carga de trabalho que precise de saídas acionadas por temporizadores — heartbeats de IoT, rastreamento de sessões, alertas em tempo real, monitoramento de equipamentos — pode ser criada da mesma forma.
Temporizadores no transformWithState tornam isso possível. Uma única classe StatefulProcessor lida com todo o ciclo de vida da sessão — processamento reativo de entrada e saída proativa acionada por temporizadores. Combinado com o Real-Time Mode, os registros de entrada são processados e os temporizadores são acionados com precisão de subsegundos — não no próximo intervalo de lote, mas agora. Tudo dentro do Databricks, sem a necessidade de um segundo mecanismo.
Se você já executa pipelines do Structured Streaming no modo micro-batch e está buscando um segundo mecanismo para obter menor latência, experimente o Real-Time Mode primeiro. A mudança é apenas uma alteração de trigger — sem reescritas, sem replataformização:
Experimente você mesmo:
O Real-Time Mode agora está em Disponibilidade Geral.
(Esta publicação no blog foi traduzida utilizando ferramentas baseadas em inteligência artificial) Publicação original
Assine nosso blog e receba os posts mais recentes diretamente na sua caixa de entrada.