Skip to content
hello tis
Go back

[26.10.28] ClickHouse 800억 건 집계 비용 줄이기

상황

800억 건 규모의 PC 기능 통계를 추가하면서, 적재한 데이터를 대시보드에서 조회할 수 있도록 집계를 확장했습니다. 이 글에서는 공통 집계의 재사용과 집계 방식별 비용, 조회 병목 개선을 정리합니다. Splunk 데이터의 적재 구조와 건수 확인 부하는 앞선 글에 모았습니다.

4코어, 메모리 16GB인 EC2 한 대에서 알매니저 이벤트 적재, PC 기능 통계의 1분 주기 적재와 1년치 백필, 광고와 삭제 코호트 집계가 실행됐습니다. 오전 CPU 사용량은 평균 3.4코어였고, PC 기능 개요의 차트 요청은 평균 30초가 걸렸습니다.

공통 집계를 재사용해 조회 확장하기

집계를 작게 만들수록 재사용할 정보도 줄어듭니다. 그래서 공통 일 집계에는 분석 기준과 Aggregate State를 남기고, 자주 쓰는 조회 결과는 더 작게 집계한다는 기준을 세웠습니다. 기기 수처럼 중복을 제거해야 하는 값은 확정된 숫자를 더하는 대신 State를 병합할 수 있어야 합니다. (Aggregate State 병합)

공통 일 집계를 입력으로 새 조회용 Refreshable MV를 만들면, Log Ingester를 멈추고 기존 데이터를 다시 채우는 대신 수집을 계속하면서 조회를 확장할 수 있다고 봤습니다. 다만 수집을 계속할 수 있다는 이점과 이후 반복 재계산 비용은 함께 고려해야 했습니다.

공통 일 집계에서 새 용도별 Refreshable MV와 조회 결과로 확장하는 경로

반복 집계 비용을 줄이기 위한 Incremental MV 전환

처음에는 기존 데이터와 계속 추가되는 데이터를 함께 재계산할 수 있어, 그래프용 제품별 일 집계에 Refreshable MV를 적용했습니다. 일별 그래프에서 날짜와 제품별로 다시 묶는 계산을 미리 저장하려는 선택이었습니다.

MV 갱신과 Rill 캐시 주기는 각각 15분으로 설정했습니다. 재계산이 갱신 주기 안에 끝나고 캐시가 15분 안에 새 결과로 전환될 때, 최대 약 30분에 재계산 시간 T를 더한 반영 지연이 생기는 조건이었습니다. (Rill 캐시 동작)

하지만 제품별 일 집계는 하루치만 바뀌어도 15분마다 1년치를 재계산해, 갱신에 주기의 평균 58%를 썼습니다.

구분Incremental MVRefreshable MV
실행 시점데이터 적재 시설정한 갱신 주기
계산 범위새로 들어온 데이터만 처리쿼리가 지정한 범위 전체를 재계산
결과 반영새 계산 결과를 추가하고 병합기존 결과를 새 결과로 전체 교체
최신성적재와 함께 반영다음 갱신이 끝난 뒤 반영
연산 비용적재 시 연산 추가갱신 시 CPU와 메모리 부하 집중

먼저 갱신 주기를 15분에서 1시간으로 늘렸습니다.

주기를 늘려도 계산 범위는 그대로여서, 제품별 일 집계를 Incremental MV로 전환했습니다.

제품별 일 집계 방식시간당 CPU초(평균)반영 주기
15분 주기 Refreshable MV2,00015분
1시간 주기 Refreshable MV, 중간 단계5501시간
Incremental MV0.31분

공통 일 집계에 저장된 uniq 상태는 새 입력의 상태와 병합할 수 있어, 기기 수를 구할 때 과거 데이터를 다시 읽을 필요가 없었습니다. 원본과 공통 일 집계는 유지하고 제품별 집계의 계산 방식만 바꿨습니다. 적재 시 연산을 추가하는 대신 조회와 경쟁하던 반복 재계산과 갱신 대기를 없앴습니다.

갱신 시점에 1년치를 읽어 결과를 교체하던 방식과 새 입력으로 상태를 추가하는 방식의 실행 순서

코호트 OOM을 막기 위한 데이터 결합 방식 변경

광고와 삭제 코호트는 같은 달의 사용 기기를 광고 노출 수준별로 묶어 다음 달 삭제율을 비교합니다. 제품과 기기를 기준으로 세 기록을 조합합니다.

9월 광고 노출과 10월 삭제 여부를 연결하듯, 관찰 기간이 끝날 때까지 재계산이 필요합니다.

전날에는 이 조회를 위해 두 월 집계를 입력으로 받는 Refreshable MV를 추가했습니다.

기존 수집과 월 집계를 유지하고 조합한 결과를 Rill에 연결했습니다.

제품 이벤트와 광고 노출의 월 집계를 Refreshable MV로 결합해 Rill에서 조회하는 구조

라이선스, 기능 사용량과 활성 일수로 나눠 광고 노출과 다음 달 삭제율을 비교했습니다. 아래는 가상 제품 A의 비교 예시입니다.

가상 제품 A의 광고 노출별 다음 달 삭제율을 라이선스, 기능 사용량, 활성 일수로 나눈 비교

JOIN의 오른쪽 입력인 수백만 기기의 해시 테이블에 메모리 13.77GiB를 할당하려다 OOM이 발생했습니다.

JOIN을 UNION ALL과 GROUP BY로 바꿔, 디스크 I/O를 더 쓰는 대신 중간 집계의 메모리를 제한했습니다. (외부 집계 동작)

백필 완료 후 갱신에는 50분이 걸렸습니다. 다른 작업과의 경합을 줄이도록 갱신 주기도 6시간에서 하루 한 번 새벽 4시로 늘렸습니다.

JOIN과 UNION ALL 후 GROUP BY의 코호트 집계 구조 비교

첫 조회를 빠르게 하기 위한 대시보드용 집계 추가

제품별 합계만 필요한 차트도 버전과 기능 코드까지 나눈 집계를 매번 다시 합치고 있었습니다. 앞선 실험에서는 Rill 캐시와 singleflight로 중복 조회의 CPU 부하를 줄였습니다. 다만 캐시에 없는 조회 조건이면 집계를 다시 실행해야 했습니다.

방식줄이는 비용첫 조회에 미치는 영향추가 비용과 조건
Rill singleflight진행 중인 같은 요청의 중복 실행한 번은 계산하고 나머지는 결과를 기다림. 동시 경합은 감소같은 캐시 키의 동시 요청에 적용
Rill 결과 캐시완료된 같은 쿼리의 재실행캐시 미스면 계산, 히트면 결과 재사용캐시 보관과 무효화 관리, 갱신 확인 주기에 따른 반영 지연
대시보드용 집계조회 한 번에 읽고 합치는 데이터량캐시가 없어도 미리 만든 집계를 조회별도 저장 공간과 적재 또는 주기적 갱신 연산

캐시와 singleflight를 유지하고 대시보드용 집계를 추가했습니다. (Rill 캐시 설정)

PC 쿼리는 유휴 상태의 서버에서 ClickHouse 쿼리 캐시를 끄고 비교했습니다.

조회기존 월 집계새 집계 적용 시
제품과 버전 피벗12.9초2.0초
기능별 기기 수 순위24초15초, 채택하지 않음

제품별 기기 수와 전체 합계 조회는 평균 600ms 걸렸습니다.

알매니저의 기존 가운데 차트는 평균 11초 걸렸습니다. 적용 후에는 Rill 캐시를 비운 콜드 로드와 캐시를 재사용한 웜 로드를 비교했습니다.

대시보드콜드 로드웜 로드
알매니저 개요가장 느린 요청 1.2초1초
PC 기능 개요전체 로딩 30초, 가장 느린 요청 17초1.3초

콜드 로드에서 PC의 기능별 기기 수 순위와 상세 표는 평균 16초 걸렸습니다.

두 조회는 새 집계를 적용해도 효과가 작았고, 큰 기기 수 집계 상태를 동시에 병합하다 계정 메모리 한도 6GB를 넘어 조회 OOM 2건이 발생했습니다. 두 조회는 기존 월 집계로 롤백하고, 기능 코드별 집계는 기기 수 상태를 병합하지 않는 차트에만 적용했습니다.

기능 코드별 집계가 추가 용량의 70%를 차지하면서 조회 효과는 작았습니다. 요약에 없는 필터는 기존 테이블로 폴백합니다.

PC 집계 4개의 12개월 지표는 기준 집계와 차이가 없었습니다. 개요의 사용 횟수 823.8억과 기기 수 1,032만도 전후가 같았습니다.

적재와 Incremental MV에서 월 집계별로 분기하고 Rill이 차트별 집계를 조회하는 구조

적재 중단을 줄이기 위한 대시보드용 집계의 갱신 방식 검토

Incremental MV 생성 시 초기 백필과 신규 적재가 겹치면 중복 집계될 수 있습니다. 알매니저는 집계 정의를 바꿀 때마다 수집 서버 2대의 Vector를 중단해야 해 대시보드 반영이 늦어졌습니다.

기본 집계는 Incremental MV로 유지하고, 입력이 작은 대시보드용 집계만 Refreshable MV로 바꾸는 안을 검토했습니다. 전환 기준은 입력 건수와 집계 상태의 크기, CPU와 메모리 비용으로 정합니다.

알매니저 집계 쿼리 하나는 기본 월 집계 40만 행을 읽어 2코어 조건에서 5초 걸렸습니다. 월 단위 개요에는 1시간 주기의 갱신도 충분하다고 봤습니다.

Refreshable MV로 전환하기 전에는 다음을 검증합니다.

알매니저는 현재 모두 Incremental MV를 사용하며, Refreshable MV 전환은 검토 중입니다.

기본 집계는 Incremental MV로 유지하고, 대시보드용 집계는 입력 건수와 계산 비용에 따라 Incremental MV와 Refreshable MV를 선택하는 구조


Share this post:

Previous Post
[26.10.29] 학습: 주문 데이터를 여러 DB로 나누기 위한 샤딩 설계하기
Next Post
[26.10.27] ClickHouse 800억 건 적재 비용 줄이기