Improving Toss Securities Ranking Service Architecture with ClickHouse
15주차: ClickHouse로 토스증권 랭킹 서비스 구조 개선하기
🚀 토스증권 랭킹 서비스, ClickHouse로 구조 개선하기
📝 들어가며
토스증권은 주식/ETF/채권 등 다양한 종목에 대해 실시간 랭킹 서비스를 제공합니다.
사용자는 앱에서 "거래량 TOP10", "급상승 종목", "업종별 인기" 등을 확인할 수 있고, 이 기능은 사용자 경험에 큰 영향을 미칩니다.
하지만 기존 구조는 분 단위 배치 처리, 복잡한 파이프라인, DW(데이터 웨어하우스)와 리소스 충돌 때문에 한계에 부딪혔습니다.
이 글에서는 토스증권 데이터 엔지니어링 팀이 ClickHouse를 도입해 실시간 아키텍처를 구축한 과정을 정리합니다.
🚨 문제 상황: 실시간성 요구 증가
기존 업데이트 주기: 1분 단위
집계 시간: 평균 10초 이상
사용자 니즈: 초 단위 실시간 랭킹 반영
즉, 배치 기반 DW 파이프라인 구조에서는 한계가 뚜렷했습니다.
특히 거래량이 폭증하는 장중에는 랭킹 반영이 늦어지거나 실패하는 사례도 발생했습니다.
👉 정리:
병목 원인 = 배치 잡 + DW 쿼리 경합
결과 = 초단위 업데이트 불가, 운영/개발 난이도 상승
🔍 원인 분석: 기존 아키텍처의 구조적 한계
실시간 이벤트(체결·시세·클라이언트 로그)를 **데이터 레이크(HDFS/S3)**에 쌓고, **DW(Impala/Presto)**로 주기적 집계를 돌린 뒤, 결과를 서비스용 저장소(RDB/캐시)에 밀어 넣어 앱이 읽게 하는 구조.
1. Airflow 기반 잡 확장성 한계
랭킹별로 Airflow DAG(Job)이 선형적으로 늘어났습니다.
옵션이 추가될수록 잡이 기하급수적으로 늘어나 관리 난이도가 폭발.
2. DW 자원 경합
분석가들이 DW에 무거운 쿼리를 날림 → 랭킹 집계 지연/실패
서비스와 분석 리소스를 분리하지 못한 구조
3. 데이터 처리 지연
로우 데이터 → DW 적재 → 집계 → 결과 추출
전체 파이프라인이 무겁고 지연에 취약
🏗️ 새로운 접근: 실시간 데이터 플랫폼 필요
토스증권 팀은 “랭킹에 필요한 데이터는 한곳에 모으고, 실시간 집계가 가능한 플랫폼이 필요하다”는 결론을 냈습니다.
👉 후보 기술을 리서치한 결과, ClickHouse가 선택되었습니다.
🏗️ ClickHouse란?
📌 정의
ClickHouse는 **오픈소스 컬럼 지향(column-oriented) 데이터베이스 관리 시스템(DBMS)**이에요.
특히 **대규모 데이터의 집계/분석(OLAP)**에 특화된 데이터베이스입니다.
📊 OLAP vs OLTP (왜 ClickHouse가 필요한가?)
OLTP (Online Transaction Processing)
은행 계좌 이체, 주문 처리 같은 트랜잭션 처리용 DB (예: MySQL, PostgreSQL)
초당 수천~수만 건의 "작은" 트랜잭션 처리에 강점
데이터는 보통
행(row)
단위 저장
OLAP (Online Analytical Processing)
대규모 데이터 집계·분석 (예: “지난 1년간 매출 TOP 10 상품”)
수억 건 데이터를 빠르게 SUM, COUNT, GROUP BY 해야 함
데이터는
열(column)
단위 저장 → 집계 시 필요한 컬럼만 읽으므로 빠름
👉 ClickHouse = OLAP 전문 DB
즉, 대규모 데이터를 빠르게 집계하고 실시간 분석하는 데 강합니다.
⚡ ClickHouse의 주요 특징
1. 컬럼 지향 저장
보통 RDB(MySQL)는 행 단위 저장 → 한 레코드 전체가 디스크에 저장
ClickHouse는 열 단위 저장 → 특정 컬럼만 빠르게 읽을 수 있음
예:
SELECT SUM(volume) FROM trades;
→
volume
컬럼만 읽으면 되므로 수십 배 빠름
2. MergeTree 엔진
ClickHouse의 기본 테이블 엔진
데이터를 파티션 단위로 쌓고, 백그라운드에서 자동 병합(merge)
대량 데이터(수십억 row)를 효율적으로 저장하고 조회 가능
파생 엔진:
ReplacingMergeTree
: 중복 제거 + 최신 레코드 유지AggregatingMergeTree
: 집계 함수 결과를 미리 저장SummingMergeTree
: 합계 미리 저장
👉 랭킹 서비스 최적화 포인트: “최신 데이터만 필요” or “중간 집계 필요”에 맞는 엔진 선택 가능
3. Materialized View
실시간 ETL(Extract-Transform-Load) 지원
Kafka에서 들어오는 데이터를 받아, 필터링/집계/조인을 한 뒤 다른 테이블에 저장 가능
장점:
Airflow 잡 같은 배치 불필요
데이터 인입 순간 실시간 반영
4. 초고속 집계 성능
페이스북, Uber, Yandex, Cloudflare 등 대규모 트래픽 기업들이 사용
수십억 건 데이터도 수백 ms 내에 집계 가능
⚡ ClickHouse가 선택된 이유
OLAP(Online Analytical Processing) 컬럼 기반 DB
빠른 집계 성능 (대용량 데이터 집계에 최적화)
단순한 운영 구조 (복잡한 Hadoop/Hive 대비 가벼움)
특화 기능:
다양한 Table Engine (MergeTree, AggregatingMergeTree, ReplacingMergeTree 등)
Materialized View (실시간 ETL/집계 가능)
📡 실시간 데이터 수집: Kafka Engine vs Sink Connector
Kafka Engine: ClickHouse 안에
ENGINE=Kafka
테이블을 만들어 CH 프로세스가 직접 토픽을 consume. 보통 Materialized View(MV) 로 변환·적재를 트리거해 타겟 MergeTree 테이블에 넣는 구조.Sink Connector: Kafka Connect(외부 워커)가 토픽을 consume 해서 바로 ClickHouse MergeTree 테이블에 INSERT. 변환/스키마/에러 처리/재시도 등을 커넥터 레이어에서 담당.
전자: Kafka (topic) → [ENGINE=Kafka 테이블] → (MV 트리거) → MergeTree 타겟
후자: Kafka (topic) → Kafka Connect (Sink Connector) → ClickHouse MergeTree
Kafka Engine
ClickHouse 자체에서 Kafka 토픽을 직접 consume 가능
장점: 외부 의존성 없음
단점:
ClickHouse 서버와 Kafka consumer 리소스 공유 → 성능 불리
테이블 세트가 많아 관리 복잡
Clickhouse Sink Connector
Kafka Connect 기반의 ClickHouse Sink Connector 활용
독립적으로 관리 가능, 리소스 분리
운영 편의성 ↑, 확장성 ↑
👉 결론: Kafka Engine 대신 Sink Connector를 도입
🔄 CDC(Change Data Capture) 도입
CDC = 원본 DB(MySQL/PG)에서 일어나는 Insert/Update/Delete를 binlog/Logical decoding으로 캡처해 다운스트림(ClickHouse 등)으로 흘려보내는 기술.
Append-only: 기존 행을 직접 고치지 않고, 같은 키(예:
symbol
)에 대해 새 버전 행을 한 줄 더 INSERT 합니다.엔진이
ReplacingMergeTree(version)
이면, 논리적으로 최신 버전만 보이도록 설계합니다
랭킹에는 메타데이터 변경 반영도 필요합니다.
예:
종목 상장/상폐
관심 종목 설정/해제
ClickHouse는 MaterializedMySQL Engine을 통해 CDC 기능을 제공합니다.
MySQL binlog를 읽어 ClickHouse에 반영
테이블 단위 복제 가능
단점: 아직 일부 기능 제약 존재(실험적 기능) → Sink Connector와 혼합 사용
🗂️ ReplacingMergeTree로 최신 데이터만 유지
특히 급상승/급하락 랭킹은 “가장 최근 가격”만 필요합니다.
기존: 중복된 체결 데이터 다 저장 → 집계 시 리소스 낭비
개선:
ReplacingMergeTree
엔진 사용Key + Version 컬럼 지정
최신 데이터만 유지 → 디스크 공간 절약 + 빠른 집계
🧮 AggregatingMergeTree로 집계 최적화
인기 랭킹은 클라이언트 로그 기반인데, 시간당 1억 건 이상 발생합니다.
로우 데이터 직접 집계: 수백 ms ~ 1초 소요
해결책:
중간 집계 테이블 생성
AggregatingMergeTree
+Materialized View
사용초/분/시간 단위로 미리 집계 저장
최종 쿼리 시 로우 데이터를 읽을 필요 없음
👉 성능 개선:
기존: 600~700ms
개선: 200~300ms
🔑 핵심 아키텍처 설계
데이터 인입
Kafka → ClickHouse (Sink Connector)
MySQL CDC → ClickHouse (MaterializedMySQL Engine)
실시간 집계
Materialized View로 필터링/조인/집계
ReplacingMergeTree / AggregatingMergeTree 엔진 활용
결과 제공
애플리케이션에서 초단위 랭킹 쿼리
캐시 계층 병행 활용
📊 성능 검증
테스트 토픽: 초당 70만 건 데이터 유입
클러스터: 서버 5대 구성
결과:
Kafka → ClickHouse 인입: 초당 60만 건 안정 처리
집계 쿼리 응답 속도: 평균 200~300ms
장중 트래픽 폭증에도 안정적 동작
🛡️ 운영 측면 개선
분석 파이프라인과 서비스 파이프라인 분리
→ 분석 쿼리 경합 제거
Airflow DAG 폭발 문제 해소
→ 옵션별 잡 생성 불필요, Materialized View 자동 처리
운영 단순화
→ 관리 포인트 감소, 장애 원인 추적 용이
🎯 교훈과 인사이트
배치 기반 DW 한계 극복
→ 실시간 서비스에는 별도의 플랫폼 필요
Table Engine 전략적 활용
ReplacingMergeTree: 키값으로 최신값 유지
AggregatingMergeTree: 컬럼별로 중간 집계
MergeTree: 대량 인서트/쿼리 처리
실시간성과 운영 편의성의 균형
Kafka Engine 대신 Sink Connector 선택
분석 vs 서비스 자원 분리
서비스 안정성을 위해 필수
🧑💻 개발자를 위한 용어 주석
DW(Data Warehouse): 기업의 데이터 분석을 위한 중앙 저장소
Airflow DAG: 워크플로우를 정의하는 그래프 구조 (잡 실행 순서 정의)
OLAP: 대용량 데이터를 다차원으로 분석하는 방식
CDC: 원본 DB의 변경을 실시간으로 다른 시스템에 반영하는 기법
Materialized View: 쿼리 결과를 미리 저장해두는 뷰 (실시간 ETL 가능)
MergeTree: ClickHouse의 기본 스토리지 엔진, 대량 데이터 처리에 최적화
🔮 앞으로의 확장 가능성
다른 서비스(알림/추천)에도 ClickHouse 적용 가능
타임시리즈 분석 (분 단위 시세 변동 등) 최적화
서빙용 + 분석용 ClickHouse 이중화
✅ 마무리
토스증권은 ClickHouse 기반 실시간 데이터 플랫폼으로 전환하면서:
랭킹 집계 속도: 10초 → 200ms
운영 안정성: 분석/서비스 분리
개발 생산성: 잡 관리 단순화
👉 교훈: 실시간 서비스는 “분석 중심 DW”가 아니라 “서비스 중심 OLAP DB” 위에서 설계해야 한다.
배운점
ClickHouse는 append-only 구조에 다양한 엔진(Replacing, Aggregating)을 조합해 업데이트/집계 문제를 효율적으로 해결할 수 있다는 걸 배웠습니다.
Kafka Engine과 Sink Connector는 각각 장단이 있지만, 대규모 실서비스에서는 Sink Connector가 더 안정적이라는 점이 인상적이었습니다.
Redis는 단독으론 지연 이벤트·가변 윈도우 처리에 한계가 있어, ClickHouse 결과를 캐싱하는 보완재로 쓰는 게 적합하다는것을 배웠습니다.
결국 핵심 교훈은 “데이터는 쉽게 쌓고, 읽기·집계 최적화는 DB와 캐시를 적절히 결합해 푼다”는 설계 철학이라는 것을 배웠습니다.
Last updated