Como a Roblox usou o Theta Sketches para ampliar a análise de criadores

A análise de dados é essencial para os jogos multijogador em tempo real de hoje. Na Roblox, estamos focados no desenvolvimento de ferramentas de medição para ajudar nossos criadores a prosperar. Nossa análise de dados gratuita e pronta para uso oferece aos criadores insights instantâneos sobre o crescimento de suas experiências, a aquisição e a retenção de usuários, ajudando-os a maximizar seu sucesso.
Construir os sistemas de análise atualizados dos quais milhões de criadores da Roblox dependem é um desafio importante. Para enfrentá-lo, otimizamos nosso mecanismo de consulta analítica para que um cluster de processamento de 120 núcleos possa atender a mais de 6 milhões de consultas por dia de aproximadamente 300.000 visitantes diários que acessam 86 TB de dados. No centro da nossa solução está um banco de dados de processamento analítico online (OLAP) que escolhemos por sua escalabilidade e integração com algoritmos de aproximação. Usando uma combinação de técnicas de rollup de dados com os algoritmos HyperLogLog e Theta Sketch, fornecemos análises para milhões de experiências do Roblox1.
Introdução à análise OLAP
Quanto mais dados são consultados, mais tempo leva para gerar resultados. Quando conseguimos reduzir os dados necessários e acelerar o processo de análise, os criadores podem obter insights quase em tempo real a partir de suas ações. Algumas das técnicas que utilizamos incluem:
- Armazenamento em colunas: o OLAP, Druid, lê apenas as colunas necessárias.
- Filtros de partição e classificação: o OLAP lê apenas os arquivos relevantes que indexam diretamente os blocos de dados necessários.
- Rollup: o OLAP agrega parcialmente eventos usando agrupamentos comuns.
Os rollups, em particular, permitem que os OLAPs operem entre os maiores mecanismos de consulta SQL, como Spark ou Presto (com latências de dezenas de segundos), e consultas pontuais ou SQL limitado, que geralmente fornecem dados totalmente agregados. Com os rollups, as consultas passam a ser indexadas por agrupamentos de dimensões, resultando em grandes reduções na cardinalidade total das linhas. Ao analisar bilhões ou até trilhões de eventos brutos, pode ser muito mais eficiente agrupá-los em milhões de agrupamentos que podem ser agregados com latência inferior a um segundo. Por exemplo:

Embora os rollups ofereçam as vantagens de redução mencionadas acima, certas métricas são resistentes a eles, incluindo consultas que exigem uma classificação completa da tabela de dados brutos, como contagens distintas, percentis e consultas de frequência.
Felizmente, podemos contornar essas limitações com técnicas que retornam um resultado aproximado estatisticamente limitado, com base em estruturas de dados complexas que contêm uma amostra do conjunto de dados completo. Essas estruturas de dados são projetadas para serem usadas em técnicas de rollup e combinam duas contagens distintas por meio de uma operação de união, semelhante à soma de dois números.
Analisando as cargas de trabalho do Roblox Analytics
Na Roblox, oferecemos aos criadores um painel centralizado onde podem encontrar suas principais métricas. Entre elas estão:
- Engajamento: usuários ativos diários (DAU), usuários ativos mensais (MAU), retenção e funis
- Monetização: receita, receita média por usuário, vendas e economia
- Dados de aquisição
- Personalização de miniaturas e resultados de experimentos
- Análise de recomendações na página inicial
- E muito mais por vir.

Escolhendo e otimizando o mecanismo de consulta
Superando desafios de desempenho
Em uma rodada final de testes de produção em ambiente de teste, descobrimos um desafio importante: o desempenho das consultas MAU precisava ser reforçado após a mudança de consultas únicas de grande porte para padrões de agregação diária. Isso é crucial para nossas visualizações de análise de criadores.
Descobrimos que a estrutura da consulta afetava significativamente o desempenho subjacente da nossa solução OLAP. Consultas padrão com múltiplas etapas de execução (como instruções “GROUP BY” aninhadas2) frequentemente transferem grande parte do trabalho para os nós de broker mais leves.
Esse é um problema clássico de big data, em que parte de uma consulta acaba sendo executada em pequenos nós de serviço importantes. Esperávamos que nossas estruturas de dados aproximadas funcionassem como simples contagens ou somas, mas descobrimos que elas, na verdade, se comportavam de maneira muito diferente.
A figura abaixo ilustra o problema. Ela mostra como nossos nós históricos realizariam uma agregação parcial, acumulando um Theta Sketch para cada dia e, em seguida, enviando seus dados de volta para o broker. O broker então tentava mesclar cada grande esboço diário em um único valor mensal por dia. Para 30 dias de MAU, isso significava mesclar 1.800 Theta Sketches de tamanho máximo em um broker, o que resultou em uma consulta mais lenta e propensa a falhas que monopolizava a CPU do broker.

Nossa solução foi executar o OLAP com menos processadores históricos de grande porte para maximizar a localidade dos dados para fontes que dependiam de consultas de aproximação. Na prática, isso transferiu uma operação de mesclagem que poderia ter exigido mais de 100 MB de processamento de dados de volta para nossos nós históricos.
Para conseguir isso no SQL, usamos uma junção inline para fazer com que as consultas propagassem as informações necessárias aos nós históricos e preparamos uma consulta com uma lista de datas de resultados inline. Cada data de resultado pode então coletar os dados relevantes dos segmentos dos nós históricos. Os dados são então repassados ao broker, onde os resultados são rapidamente mesclados em um único mapa de data de resultado para dados métricos, como visto abaixo.

Essa otimização teve um impacto dramático no desempenho de consultas em grande escala. Para a divisão por país do MAU de uma experiência importante, o desempenho médio das consultas melhorou em 5 vezes (de 17,53 segundos para 3,23), conforme mostrado no gráfico abaixo. Também observamos uma redução de 50 vezes no tempo de CPU no broker (de 16,83 segundos para 0,34).
Embora os resultados variem, isso destaca a importância de tratar operações complexas (como a fusão de milhões de esboços) com cuidado. Presumir que essas operações são equivalentes a agregações simples pode levar a problemas significativos de desempenho, especialmente em sistemas onde agregações de clientes de última milha são comuns.
Rollups e um cubo theta teórico

Também exploramos um cubo theta, ou seja, uma abordagem generalizada para preencher a lacuna entre tabelas de rollup básicas e tabelas totalmente brutas por meio de interseções aproximadas de conjuntos. Essa abordagem resolve uma limitação fundamental: as tabelas de rollup perdem sua vantagem quando as consultas precisam acessar muitas camadas de dimensões de alta cardinalidade. Isso ocorre porque cada dimensão faz com que a cardinalidade do rollup seja proporcional a ∏dim (produto das dimensões).
Projetamos um sistema que agregaria por grupos de dimensões comuns com um limite de cardinalidade, permitindo consultas de desempenho de rollup em qualquer elemento do grupo. Então, ao procurar combinações de dimensões entre grupos, tentaríamos uma junção aproximada entre os conjuntos e retornaríamos os resultados métricos juntamente com estimativas de erro. Uma consulta com alta estimativa de erro seria encaminhada para uma tabela bruta, onde os diversos filtros deveriam permitir grandes otimizações de pushdown.


Como podemos calcular essa taxa de erro rapidamente, isso também serve como um forte indicador de que a leitura da tabela bruta provavelmente terá bom desempenho. Nos casos em que os dados sobrepostos são pequenos em relação à união (falantes de japonês na Alemanha, por exemplo), um grande número de linhas da tabela bruta será filtrado. Isso resulta em otimizações de pushdown eficientes. Um sistema que utilize grupos de dimensões, junções aproximadas e leituras de tabelas brutas baseadas em erros maximizaria verdadeiramente o desempenho do rollup em consultas favoráveis à aproximação.
Para a Roblox, essa solução será mais aplicável em nosso próximo nível de escala — potencialmente para funil dinâmico ou análise de eventos personalizados — enquanto nossa réplica de rollup simples atual satisfaz as necessidades de hoje.
Criação de uma plataforma de autoatendimento
Com nosso broker otimizado, voltamos nossa atenção para a criação de ferramentas para integração e consulta de conjuntos de dados adicionados à nossa solução OLAP. Criamos uma biblioteca UDAF de código aberto para Spark e Trino para nossas funções de esboço de dados, permitindo que o Spark use o mesmo formato binário de esboço de dados que nosso OLAP6. Isso manteve a maior parte de nossa carga de trabalho de computação no Spark e ajudou a padronizar a aproximação em toda a Roblox, reduzindo potencialmente os custos de computação em até 80% para determinados conjuntos de dados.
Simplificamos a integração com uma extensão interna do nosso agendador de tarefas em lote e definimos uma API no estilo dataframe que orienta os desenvolvedores a decidir sobre medidas e dimensões definitivas, reduzindo o impacto de consultas abertas. Também disponibilizamos em código aberto alguns fluxos de trabalho de exemplo sobre como carregamos e consultamos esses dados em nosso OLAP.
Nossos conjuntos de dados analíticos otimizados agora estão fornecendo insights profundos aos nossos criadores. Nossas otimizações melhoraram o desempenho médio em 4 vezes e o desempenho no pior cenário em 50 vezes. A plataforma de autoatendimento permite que nossa equipe de Creator Analytics continue iterando em novos conjuntos de dados para desenvolvedores. Estamos entusiasmados em ver desenvolvedores de todos os tamanhos usando essas ferramentas para criar experiências incríveis no Roblox.
1 Calculado com base nos últimos 60 dias de universos únicos com qualquer acesso
2 Como esta consulta
MAU simples 3 Os resultados são de 21 a 28 de março de 2025
4 Executado assim: SELECT c.experience_id, c.country, p.platform, THETA_INTERSECT(c.user_theta, p.user_theta) from (select experience_id, country, user_theta from theta_cube where agg_level = country) c union (select experience_id, platform, user_theta from theta_cube where agg_level = platform) p
5 https://datasketches.apache.org/docs/Theta/ThetaSketchSetOpsAccuracy.html
6 Por meio de uma função SQL do Druid COMPLEX_DECODE_BASE64('HLLSketch', sketch_col_name ).


