Roblox가 Theta Sketches를 활용해 크리에이터 분석 기능을 확장한 방법

오늘날의 실시간 멀티플레이어 게임에서 분석은 필수적입니다. Roblox는 크리에이터들이 성공할 수 있도록 돕는 측정 도구 개발에 주력하고 있습니다. 당사의 무료 즉시 사용 가능한 분석 도구는 크리에이터들에게 자신의 경험(Experience)의 성장, 사용자 확보 및 유지에 대한 즉각적인 통찰력을 제공하여 성공을 극대화할 수 있도록 지원합니다.
수백만 명의 로블록스 크리에이터가 의존하는 최신 분석 시스템을 구축하는 것은 중요한 과제입니다. 이를 해결하기 위해, 저희는 분석 쿼리 엔진을 최적화하여 120코어 처리 클러스터가 86TB의 데이터에 접근하는 약 30만 명의 일일 방문자로부터 하루 600만 건 이상의 쿼리를 처리할 수 있도록 했습니다. 이 솔루션의 핵심은 확장성과 근사 알고리즘과의 통합성을 고려해 선택한 온라인 분석 처리(OLAP) 데이터베이스입니다. 데이터 롤업 기법과 HyperLogLog 및 Theta Sketch 알고리즘을 조합하여, 수백만 개의 로블록스 경험1에 대한 분석 기능을 제공합니다.
OLAP 분석 입문
쿼리되는 데이터가 많을수록 결과를 산출하는 데 더 많은 시간이 소요됩니다. 필요한 데이터를 줄이고 분석 과정을 가속화할 수 있다면, 제작자는 자신의 활동에 대한 거의 실시간에 가까운 인사이트를 얻을 수 있습니다. 당사가 활용하는 기술 중 일부는 다음과 같습니다:
- 열 기반 저장: OLAP인 Druid는 필요한 열만 읽습니다.
- 파티션 및 정렬 필터: OLAP은 필요한 데이터 블록으로 직접 인덱싱된 관련 파일만 읽습니다.
- 롤업(Rollup): OLAP은 공통 그룹화를 사용하여 이벤트를 부분적으로 집계합니다.
특히 롤업(Rollup)을 통해 OLAP은 스파크(Spark)나 프레스토(Presto)와 같은 대규모 SQL 쿼리 엔진(지연 시간 수십 초)과, 일반적으로 완전히 집계된 데이터를 제공하는 포인트 쿼리 또는 제한된 SQL 사이에서 작동할 수 있습니다. 롤업을 사용하면 쿼리가 차원의 그룹화를 기준으로 키가 지정되어 전체 행 카디널리티가 크게 감소합니다. 수십억 개 또는 수조 개의 원시 이벤트를 처리할 때, 이를 1초 미만의 지연 시간으로 집계할 수 있는 수백만 개의 그룹으로 롤업하는 것이 훨씬 더 효율적일 수 있습니다. 예를 들어:

롤업은 앞서 언급한 축소 이점을 제공하지만, 고유 개수, 백분위수, 빈도 쿼리 등 원시 데이터의 전체 테이블 정렬이 필요한 쿼리를 포함하여 특정 지표는 롤업의 효과를 제대로 발휘하지 못합니다.
다행히도, 전체 데이터 세트의 표본을 포함하는 복잡한 데이터 구조를 기반으로 통계적으로 유효한 근사값을 반환하는 기법을 사용하면 이러한 한계를 극복할 수 있습니다. 이러한 데이터 구조는 롤업 기법에 사용되도록 설계되었으며, 두 개의 고유 개수를 합집합 연산을 통해 결합하는데, 이는 두 숫자를 더하는 것과 유사합니다.
Roblox 분석 워크로드 분석

쿼리 엔진 선택 및 최적화
성능 문제 극복
최종 생산 환경 섀도 테스트 과정에서 중요한 과제를 발견했습니다. 단일 대규모 쿼리에서 일별 집계 패턴으로 전환한 후, MAU 쿼리 성능을 강화해야 했습니다. 이는 크리에이터 분석 시각화에 있어 매우 중요한 요소입니다.
쿼리 구조가 OLAP 솔루션의 기본 성능에 큰 영향을 미친다는 사실을 확인했습니다. 여러 실행 단계(중첩된 "GROUP BY" 문2 등)를 포함하는 표준 쿼리는 종종 작업의 상당 부분을 경량 브로커 노드로 떠넘기곤 합니다.
이는 쿼리의 일부가 중요한 소형 서빙 노드에서 실행되는 전형적인 빅데이터 문제입니다. 당사는 근사 데이터 구조가 단순한 개수 계산이나 합계처럼 작동할 것으로 예상했으나, 실제로는 훨씬 다르게 동작한다는 사실을 발견했습니다.
아래 그림은 이 문제를 설명합니다. 이 그림은 히스토리 노드들이 부분 집계를 수행하는 방식을 보여줍니다. 즉, 매일 Theta Sketch를 롤업한 후 데이터를 브로커로 다시 전송합니다. 그런 다음 브로커는 각 대형 일별 스케치를 일별 단일 월간 값으로 병합하려고 시도합니다. 30일간의 MAU 데이터를 처리할 경우, 이는 브로커에서 최대 크기의 Theta Sketch 1,800개를 병합해야 함을 의미했으며, 그 결과 브로커 CPU를 독점하는 느리고 오류가 발생하기 쉬운 쿼리가 발생했습니다.

저희의 해결책은 근사 쿼리에 의존하는 데이터 소스의 데이터 로컬리티를 극대화하기 위해 대규모 히스토리 워커의 수를 줄여 OLAP을 실행하는 것이었습니다. 실제로 이로 인해 100MB 이상의 데이터 처리가 필요했을 수도 있는 병합 작업이 히스토리 노드로 다시 전달되었습니다.
SQL에서 이를 구현하기 위해, 인라인 조인을 사용하여 쿼리가 필요한 정보를 히스토리 노드로 전달하도록 하고, 인라인 결과 날짜 목록이 포함된 쿼리를 준비했습니다. 그러면 각 결과 날짜는 히스토리 노드 세그먼트에서 관련 데이터를 수집할 수 있습니다. 이후 데이터는 브로커로 다시 전달되며, 아래에서 볼 수 있듯이 결과는 결과 날짜와 메트릭 데이터 간의 단일 매핑으로 신속하게 병합됩니다.

이 최적화는 대규모 쿼리의 성능에 극적인 영향을 미쳤습니다. 아래 차트에서 볼 수 있듯이, 주요 서비스의 국가별 월간 활성 사용자(MAU) 분포를 분석하는 쿼리의 평균 처리 속도가 5배 향상되었습니다(17.53초에서 3.23초로 단축). 또한 브로커의 CPU 처리 시간도 50배 감소했습니다(16.83초에서 0.34초로 단축).
결과는 다양할 수 있지만, 이는 수백만 개의 스케치를 병합하는 것과 같은 복잡한 작업을 신중하게 처리해야 할 필요성을 강조합니다. 이러한 작업을 단순한 집계와 동일시할 경우, 특히 라스트 마일 클라이언트 집계가 빈번한 시스템에서 심각한 성능 문제가 발생할 수 있습니다.
롤업 및 이론적 세타 큐브

또한 우리는 근사 집합 교차를 통해 기본 롤업 테이블과 완전 원시 테이블 간의 격차를 해소하는 일반화된 접근 방식인 세타 큐브(theta cube)를 탐구했습니다. 이 접근 방식은 다음과 같은 근본적인 한계를 해결합니다. 쿼리가 높은 카디널리티 차원의 여러 계층을 다루어야 할 때 롤업 테이블은 그 장점을 상실합니다. 이는 각 차원이 롤업 카디널리티를 ∏dim(차원의 곱)만큼 증가시키기 때문입니다.
우리는 카디널리티 상한을 설정하여 공통 차원 그룹별로 집계하는 시스템을 설계함으로써, 그룹 내 모든 항목에 대해 롤업 성능 쿼리를 수행할 수 있도록 했습니다. 그런 다음 그룹 간 차원 조합을 찾을 때는 집합 간 근사 조인(join4)을 시도하고, 오차 추정치와 함께 메트릭 결과를 반환합니다. 추정 오차가 높은 쿼리는 원시 테이블로 전달되며, 여기서 다양한 필터를 통해 대규모 푸시다운 최적화를 수행할 수 있습니다.


이 오류율을 신속하게 계산할 수 있기 때문에, 이는 원시 테이블을 읽는 것이 성능 면에서 유리할 것이라는 강력한 신호로도 작용합니다. 중복 데이터가 합집합에 비해 적은 경우(예: 독일 내 일본어 사용자), 원시 테이블의 많은 행이 필터링되어 제외됩니다. 그 결과 효율적인 푸시다운 최적화가 이루어집니다. 차원 그룹, 근사 조인, 오류 기반 원시 테이블 읽기를 사용하는 시스템은 근사 처리에 적합한 쿼리에서 롤업 성능을 진정으로 극대화할 것입니다.
Roblox의 경우, 이 솔루션은 다음 단계의 확장성(예: 동적 퍼널 또는 사용자 정의 이벤트 분석)에서 더 적합할 것이며, 현재의 단순한 롤업 리플리카는 당장의 요구 사항을 충족합니다.
셀프 서비스 플랫폼 구축
브로커 최적화를 마친 후, 우리는 OLAP 솔루션에 추가된 데이터셋을 온보딩하고 쿼리하기 위한 도구 구축에 착수했습니다. 데이터스케치(datasketch) 함수를 위한 오픈소스 Spark 및 Trino UDAF 라이브러리를 구축하여, Spark가 OLAP6와 동일한 바이너리 데이터스케치 형식을 사용할 수 있도록 했습니다. 이를 통해 대부분의 컴퓨팅 워크로드를 Spark 내에서 처리할 수 있었으며, Roblox 전반에 걸쳐 근사치 계산 방식을 표준화하여 특정 데이터셋의 경우 컴퓨팅 비용을 최대 80%까지 절감할 수 있었습니다.
배치 작업 스케줄러에 내부 확장 기능을 추가하여 데이터 온보딩을 간소화했으며, 개발자가 명확한 측정값과 차원을 결정할 수 있도록 안내하는 데이터프레임 스타일의 API를 정의하여 개방형 쿼리의 영향을 줄였습니다. 또한 OLAP에서 이 데이터를 로드하고 쿼리하는 방법에 대한 몇 가지 샘플 워크플로를 오픈소스로 공개했습니다.
최적화된 분석 데이터셋은 이제 크리에이터들에게 심층적인 인사이트를 제공하고 있습니다. 이러한 최적화를 통해 평균 성능은 4배, 최악의 경우 성능은 50배 향상되었습니다. 셀프 서비스 플랫폼을 통해 크리에이터 분석 팀은 개발자를 위한 새로운 데이터셋을 지속적으로 개선해 나갈 수 있습니다. 규모에 상관없이 모든 개발자가 이러한 도구를 활용해 로블록스에서 놀라운 경험을 만들어내는 모습을 기대합니다.
1 지난 60일 동안 접속
기록이 있는 고유 사용자 집합을 기준으로 계산됨 2 다음과 같은 단순한 MAU 쿼리와 유사함
3 결과는 2025년
3월 21일부터 28일까지의 데이터임 4 다음과 같이 수행됨: 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 Druid SQL 함수를 통해 COMPLEX_DECODE_BASE64('HLLSketch', sketch_col_name ).


