Comment Roblox a utilisé Theta Sketches pour développer ses outils d'analyse des créateurs

L'analyse de données est essentielle pour les jeux multijoueurs en temps réel d'aujourd'hui. Chez Roblox, nous nous concentrons sur le développement d'outils de mesure pour aider nos créateurs à prospérer. Nos outils d'analyse gratuits et prêts à l'emploi offrent aux créateurs un aperçu instantané de la croissance de leurs expériences, de l'acquisition et de la fidélisation des utilisateurs, les aidant ainsi à maximiser leur succès.
La mise en place de systèmes d'analyse à jour sur lesquels comptent des millions de créateurs Roblox constitue un défi de taille. Pour le relever, nous avons optimisé notre moteur de requêtes analytiques afin qu'un cluster de traitement à 120 cœurs puisse traiter plus de 6 millions de requêtes par jour provenant d'environ 300 000 visiteurs quotidiens accédant à 86 To de données. Au cœur de notre solution se trouve une base de données de traitement analytique en ligne (OLAP) que nous avons choisie pour son évolutivité et son intégration avec des algorithmes d'approximation. En combinant des techniques de regroupement de données avec les algorithmes HyperLogLog et Theta Sketch, nous fournissons des analyses pour des millions d'expériences Roblox1.
Introduction à l'analyse OLAP
Plus le volume de données interrogées est important, plus l'obtention des résultats prend du temps. Lorsque nous parvenons à réduire la quantité de données nécessaires et à accélérer le processus d'analyse, les créateurs peuvent obtenir des informations en temps quasi réel sur leurs actions. Voici quelques-unes des techniques que nous utilisons :
- Stockage en colonnes : l'OLAP, Druid, ne lit que les colonnes nécessaires.
- Filtres de partition et de tri : l'OLAP ne lit que les fichiers pertinents qui indexent directement les blocs de données nécessaires.
- Rollup : l'OLAP agrège partiellement les événements à l'aide de regroupements communs.
Les rollups, en particulier, permettent aux OLAP de fonctionner entre les plus grands moteurs de requêtes SQL, comme Spark ou Presto (avec des latences de plusieurs dizaines de secondes), et les requêtes ponctuelles ou le SQL limité, qui fournissent généralement des données entièrement agrégées. Avec les rollups, les requêtes sont indexées par regroupements de dimensions, ce qui entraîne une réduction importante de la cardinalité totale des lignes. Lorsqu'on examine des milliards, voire des billions d'événements bruts, il peut être beaucoup plus efficace de les regrouper en millions de groupements pouvant être agrégés avec une latence inférieure à la seconde. Par exemple :

Si les rollups offrent les avantages de réduction mentionnés ci-dessus, certains indicateurs y sont insensibles, notamment les requêtes qui nécessitent un tri complet de la table de données brutes, comme les comptages distincts, les centiles et les requêtes de fréquence.
Heureusement, nous pouvons contourner ces limitations grâce à des techniques qui renvoient un résultat approximatif statistiquement borné, basé sur des structures de données complexes contenant un échantillon de l'ensemble de données complet. Ces structures de données sont conçues pour être utilisées dans les techniques de rollup et combinent deux comptages distincts via une opération d'union, similaire à l'addition de deux nombres.
Analyse des charges de travail liées à Roblox Analytics
Chez Roblox, nous mettons à la disposition des créateurs un tableau de bord centralisé où ils peuvent trouver les informations les plus importantes. Celles-ci comprennent :
- Engagement : utilisateurs actifs quotidiens (DAU), utilisateurs actifs mensuels (MAU), fidélisation et entonnoirs
- Monétisation : chiffre d'affaires, revenu moyen par utilisateur, ventes et économie
- Données d'acquisition
- Personnalisation des vignettes et résultats des expériences
- Analyses des recommandations sur la page d'accueil
- Et bien d'autres fonctionnalités à venir.

Choix et optimisation du moteur de recherche
Surmonter les défis liés aux performances
Lors d'une dernière série de tests en production, nous avons découvert un défi de taille : les performances de nos requêtes MAU devaient être améliorées après le passage de requêtes uniques volumineuses à des modèles d'agrégation quotidiens. Ces derniers sont essentiels pour nos visualisations d'analyses des créateurs.
Nous avons constaté que la structure de la requête affectait considérablement les performances sous-jacentes de notre solution OLAP. Les requêtes standard comportant plusieurs étapes d'exécution (comme les instructions « GROUP BY » imbriquées2) transfèrent souvent une grande partie du travail vers les nœuds de courtage légers.
Il s'agit d'un problème classique lié au big data, où une partie d'une requête finit par s'exécuter sur de petits nœuds de service importants. Nous nous attendions à ce que nos structures de données approximatives fonctionnent comme de simples comptages ou sommes, mais nous avons découvert qu'elles se comportaient en réalité de manière très différente.
La figure ci-dessous illustre le problème. Elle montre comment nos nœuds historiques effectuaient une agrégation partielle, en regroupant un Theta Sketch pour chaque jour, puis en renvoyant leurs données au broker. Le broker tentait ensuite de fusionner chaque grand sketch quotidien en une seule valeur mensuelle par jour. Pour 30 jours de MAU, cela impliquait de fusionner 1 800 Theta Sketches de taille maximale sur un courtier, ce qui entraînait une requête plus lente et sujette à des échecs, monopolisant le CPU du courtier.

Notre solution a consisté à exécuter l'OLAP avec moins de grands workers historiques afin de maximiser la localité des données pour les sources de données qui s'appuyaient sur des requêtes d'approximation. En pratique, cela a renvoyé vers nos nœuds historiques une opération de fusion qui aurait pu nécessiter le traitement de plus de 100 Mo de données.
Pour y parvenir en SQL, nous avons utilisé une jointure en ligne afin que les requêtes propagent les informations nécessaires vers les nœuds historiques, et nous avons préparé une requête avec une liste de dates de résultats en ligne. Chaque date de résultat peut alors collecter les données pertinentes à partir des segments de nœuds historiques. Les données sont ensuite renvoyées au courtier, où les résultats sont rapidement fusionnés en une seule carte associant la date de résultat aux données métriques, comme illustré ci-dessous.

Cette optimisation a eu un impact considérable sur les performances des requêtes à grande échelle. Pour la répartition par pays de l'audience mensuelle active (MAU) d'une expérience majeure, les performances moyennes des requêtes ont été multipliées par 5 (passant de 17,53 secondes à 3,23), comme le montre le graphique ci-dessous. Nous avons également constaté une réduction de 50 fois du temps CPU sur le broker (passant de 16,83 secondes à 0,34).
Bien que les résultats varient, cela souligne l'importance de traiter avec soin les opérations complexes (telles que la fusion de millions de croquis). Considérer ces opérations comme équivalentes à de simples agrégations peut entraîner des problèmes de performances importants, en particulier sur les systèmes où les agrégations client de dernier kilomètre sont courantes.
Rollups et un cube thêta théorique

Nous avons également exploré un cube thêta, c'est-à-dire une approche généralisée visant à combler le fossé entre les tables de synthèse de base et les tables entièrement brutes via des intersections approximatives d'ensembles. Cette approche remédie à une limitation fondamentale : les tables de synthèse perdent leur avantage lorsque les requêtes doivent toucher de nombreuses couches de dimensions à forte cardinalité. En effet, chaque dimension entraîne une augmentation de la cardinalité de la synthèse proportionnelle à ∏dim (produit des dimensions).
Nous avons conçu un système qui agrégerait par groupes de dimensions communs avec une limite de cardinalité, permettant ainsi des requêtes performantes de rollup sur n'importe quel élément du groupe. Ensuite, lors de la recherche de combinaisons de dimensions entre les groupes, nous tenterions une jointure approximative entre les ensembles et renverrions les résultats métriques accompagnés d'estimations d'erreur. Une requête présentant une erreur estimée élevée serait transmise à un tableau brut, où les nombreux filtres devraient permettre d'importantes optimisations par pushdown.


Comme nous pouvons calculer rapidement ce taux d'erreur, cela constitue également un indicateur fort que la lecture de la table brute sera probablement performante. Dans les cas où les données qui se chevauchent sont peu nombreuses par rapport à l'union (les locuteurs japonais en Allemagne, par exemple), un grand nombre de lignes de la table brute seront filtrées. Cela se traduit par des optimisations de pushdown efficaces. Un système utilisant des groupes de dimensions, des jointures approximatives et des lectures de tables brutes basées sur les erreurs permettrait de maximiser véritablement les performances de rollup sur les requêtes se prêtant à l'approximation.
Pour Roblox, cette solution sera plus applicable à notre prochain niveau d'échelle — potentiellement pour l'analyse dynamique d'entonnoirs ou d'événements personnalisés — tandis que notre réplique de rollup simple actuelle répond aux besoins actuels.
Mise en place d'une plateforme en libre-service
Une fois notre courtier optimisé, nous nous sommes tournés vers la création d’outils pour l’intégration et l’interrogation des ensembles de données ajoutés à notre solution OLAP. Nous avons développé une bibliothèque open source Spark et Trino UDAF pour nos fonctions de datasketch, permettant à Spark d’utiliser le même format binaire de datasketch que notre OLAP6. Cela a permis de conserver la majeure partie de notre charge de travail de calcul dans Spark et a contribué à standardiser l’approximation à l’échelle de Roblox, réduisant potentiellement les coûts de calcul jusqu’à 80 % pour certains ensembles de données.
Nous avons simplifié l'intégration grâce à une extension interne de notre planificateur de tâches par lots et défini une API de type dataframe qui guide les développeurs dans le choix des mesures et des dimensions définitives, réduisant ainsi l'impact des requêtes ouvertes. Nous avons également mis en open source quelques exemples de workflows illustrant comment nous chargeons et interrogeons ces données dans notre OLAP.
Nos ensembles de données analytiques optimisés fournissent désormais des informations approfondies à nos créateurs. Nos optimisations ont multiplié par 4 les performances moyennes et par 50 les performances dans le pire des cas. La plateforme en libre-service permet à notre équipe Creator Analytics de continuer à itérer sur de nouveaux ensembles de données pour les développeurs. Nous sommes ravis de voir des développeurs de toutes tailles utiliser ces outils pour créer des expériences incroyables sur Roblox.
1 Calculé sur les 60 derniers jours d'univers uniques ayant fait l'objet d'un accès
quelconque 2 Comme cette requête
MAU simpliste 3 Les résultats concernent la période du 21 au 28 mars 2025
4 Effectué comme suit : 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 Via une fonction SQL Druid COMPLEX_DECODE_BASE64('HLLSketch', sketch_col_name ).


