[시스템 디자인] 메달리온 아키텍쳐
서버와 DB만으로 만든 데이터 파이프라인
StarRocks + Medallion Architecture로 SSOT를 구성한 사례
1. 문제 정의
중고차 거래 플랫폼을 운영한다고 가정해보자.
전국의 딜러사들이 각자 보유한 차량 정보를 중앙 플랫폼에 등록한다. 어떤 딜러는 하루에 수십 대만 올리고, 어떤 딜러는 수천 대를 한꺼번에 밀어 넣는다.
들어오는 데이터는 기본적으로 정형이다. 그러나 등록 → 기본 검증 → 시세 산출 → 옵션 표준화 → 검색 최적화 등의 단계를 거치면서 필드가 계속 추가된다. 최종적으로는 “잘 가공된 Single Source of Truth(SSOT)”에 도달해야 하며, 이 SSOT는 약 1,000 QPS 수준의 조회 트래픽을 안정적으로 감당해야 한다. 또한 등록 시점부터 Gold 레이어에 도달하기까지 10분 이내라는 SLA가 있었다.
핵심 요구사항은 다음과 같았다.
- 여러 딜러의 데이터셋을 동시에 처리해야 한다.
- 처리 단계는 고정되어 있지 않다. 비즈니스 요구에 따라 새로운 가공 로직이 동적으로 추가될 수 있어야 한다.
- 대형 딜러의 대량 등록이 소형 딜러의 처리 지연을 유발해서는 안 된다.
- 전체 파이프라인의 운영 복잡도와 인프라 비용을 가능한 한 낮게 유지해야 한다.
2. 기술 선택의 트레이드오프 분석
데이터 파이프라인을 구성할 때 가장 흔히 거론되는 조합은 대략 다음과 같다.
| 구성 요소 | 일반적인 선택 | 장점 | 단점 |
|---|---|---|---|
| 원본 저장 | Parquet + Object Storage | 압축률 높음, 스키마 진화 유연, 비용 효율적 | 실시간 조회 성능 낮음, 별도 쿼리 엔진 필요 |
| 가공 엔진 | Spark / Flink | 풍부한 연산자, 대규모 처리에 강함, 생태계 성숙 | 클러스터 운영 비용과 복잡도 높음, 작은 작업에도 오버헤드 발생 |
| SSOT 저장소 | MongoDB | Document 모델로 유연한 스키마, 개발자 친화적 | 스키마 진화 시 마이그레이션 부담, 고QPS 조회 시 인덱스/샤딩 관리 필요 |
| 조회/분석 | Kibana (또는 유사 도구) | 강력한 시각화와 검색 | 운영 복잡도 상승, 리소스 사용량 큼 |
이 조합은 “데이터 레이크 + 스트림/배치 처리 + Document DB”라는 정석에 가깝다. 그러나 우리 요구사항과의 적합성을 따져보면 몇 가지 중요한 트레이드오프가 드러난다.
Spark/Flink 기반 접근의 트레이드오프
- 장점: 복잡한 변환, 윈도우 연산, 대규모 조인에 매우 강하다. 데이터셋 간 의존성이 복잡한 경우 사실상 표준이다.
- 단점:
- 클러스터를 항상 띄워두거나 오토스케일링을 정교하게 설정해야 한다. 소규모 딜러의 간헐적인 등록까지 동일한 오버헤드를 감수해야 한다.
- 작업 단위가 커질수록 대형 딜러의 배치가 소형 딜러의 SLA를 침범하기 쉽다 (리소스 경합).
- 운영 인력과 모니터링 체계가 추가로 필요하다.
MongoDB + Kibana 조합의 트레이드오프
- 장점: 개발 속도가 빠르고, 반정형 데이터를 자연스럽게 다룰 수 있다. 검색과 분석 UI가 즉시 제공된다.
- 단점:
- Document 모델은 필드가 단계적으로 추가되는 상황에서는 오히려 마이그레이션과 하위 호환성 관리 비용을 높인다.
- 고QPS 조회를 안정적으로 유지하려면 인덱스 설계, 샤딩, 핫스팟 관리에 지속적인 노력이 들어간다.
- Kibana(또는 유사 도구)의 운영 복잡도까지 더해지면, “파이프라인 자체”보다 “운영 도구”에 더 많은 시간을 쓰게 될 위험이 있다.
StarRocks Primary Key 테이블 + Routine Load 접근의 트레이드오프
- 장점:
- 단일 시스템 안에서 적재·가공·조회를 어느 정도 통합할 수 있다.
- Primary Key 모델의 partial column update를 활용하면, 같은 row의 서로 다른 컬럼을 여러 처리기가 간섭 없이 병렬로 갱신할 수 있다.
- 별도의 대규모 연산 클러스터 없이 애플리케이션 서버 + DB만으로 파이프라인을 구성할 수 있다.
- 목표 QPS(약 1,000)와 10분 SLA를 만족하는 수준에서는 성능과 운영 단순성 사이의 균형이 좋았다.
- 단점:
- 매우 복잡한 스트림 조인, 대규모 집계, 정교한 윈도우 연산이 필요해지면 한계가 명확하다.
- 스키마 진화가 극단적으로 빈번할 경우 컬럼 추가와 버전 관리 비용이 발생한다.
- 재처리, 모니터링, 장애 복구 로직을 상당 부분 직접 구현해야 한다.
- “데이터 레이크” 수준의 장기 보관과 임의 분석에는 별도의 전략이 필요하다.
결론적으로, 복잡한 분석 파이프라인이나 초대규모 처리가 주가 되는 환경이라면 Spark/Flink + 데이터 레이크가 더 적합하다.
반면 단계적 필드 추가 + 중간 수준의 QPS + 엄격한 단건 SLA + 운영 단순성이 중요한 경우에는 StarRocks 기반의 가벼운 메달리온 구조가 더 합리적인 선택지가 될 수 있다.
3. 아키텍처: Bronze → Silver → Gold
StarRocks 테이블을 메달리온 아키텍처의 세 레이어로 나누었다.
| 레이어 | 역할 | 특징 |
|---|---|---|
| Bronze | 원본 데이터 적재 | 딜러가 보낸 데이터를 거의 그대로 저장. 최소 검증만 수행 |
| Silver | 중간 가공 | 시세 계산, 옵션 표준화, 중복 제거 등 비즈니스 로직이 적용된 상태 |
| Gold | SSOT | 검색·조회에 최적화된 최종 형태. QPS 약 1,000 목표를 담당 |
데이터 흐름은 다음과 같다.
- 딜러 시스템 → 메시지 큐 (Kafka 등)
- Routine Load로 Bronze 테이블에 실시간 적재
- 애플리케이션 서버(또는 간단한 워커)가 Bronze를 읽어 필요한 가공을 수행한 뒤, 동일한 Primary Key로 Silver 테이블의 특정 컬럼들을 업데이트
- Silver에서 필수 가공이 모두 완료되면 Gold로 승격
- Gold 테이블이 실제 서비스 조회의 SSOT 역할을 수행
승격은 “상태 컬럼 + 조건 검사” 방식으로 구현했다.
특정 컬럼들이 모두 채워지고 유효성 검사를 통과하면 Gold로 upsert하는 단순한 로직이다. 별도의 무거운 오케스트레이션 도구 없이도 동작한다.
4. Routine Load를 활용한 컬럼 단위 병렬 처리
이 구조의 핵심은 StarRocks Primary Key 테이블의 partial column update 특성에 있다.
하나의 차량 레코드(Primary Key)에 대해 다음과 같은 처리기가 동시에 존재할 수 있다.
- 시세 계산기 →
price_estimated,price_confidence컬럼 업데이트 - 옵션 표준화기 →
normalized_options,option_score컬럼 업데이트 - 검색 키워드 생성기 →
search_keywords,search_tokens컬럼 업데이트
Routine Load와 애플리케이션 레벨의 upsert를 조합하면, 각 처리기가 자신이 담당하는 컬럼만 갱신하기 때문에 서로 덮어쓰는 문제가 발생하지 않는다.
새로운 가공 단계가 필요할 때도 Silver 테이블에 컬럼을 추가하고, 해당 컬럼만 담당하는 처리기를 추가하면 된다. 기존 처리기들은 영향을 받지 않는다.
이 방식 덕분에 “동적 단계 추가”라는 요구사항을 비교적 낮은 복잡도로 만족시킬 수 있었다.
5. 대형/소형 데이터셋 격리 전략
대형 딜러의 대량 등록이 소형 딜러의 10분 SLA를 깨뜨리지 않도록 다음과 같은 조치를 취했다.
- 딜러 규모나 우선순위에 따라 Routine Load Job을 분리
- 필요 시 StarRocks Resource Group을 활용해 CPU/메모리 할당을 차별화
- 긴급하거나 소규모인 데이터는 별도 경로로 빠르게 Gold까지 올리도록 설계
완벽한 격리는 아니지만, “하나의 대형 작업이 전체 파이프라인을 멈추게 하는” 현상은 효과적으로 완화할 수 있었다.
6. 결과와 남은 과제
- 등록 후 평균 10분 이내에 Gold 도달이라는 SLA를 안정적으로 만족했다.
- SSOT 조회 QPS 약 1,000 수준을 StarRocks 테이블로 감당했다.
- 별도의 대규모 연산 클러스터 없이 애플리케이션 서버 + StarRocks만으로 파이프라인을 운영할 수 있었다.
다만 다음과 같은 한계는 명확히 존재한다.
- 복잡한 스트림 조인이나 대규모 집계가 필요해지면 이 구조만으로는 부족하다.
- 스키마 진화가 매우 빈번할 경우 컬럼 관리 비용이 증가한다.
- 재처리·모니터링·장애 복구는 상당 부분 직접 구현해야 한다.
- 장기 보관 및 임의 분석용 데이터 레이크는 별도로 설계해야 한다.
7. 마치며
모든 상황에 “정석” 스택이 최선은 아니다.
단계적으로 필드가 추가되고, 단건 처리 SLA가 중요하며, 중간 수준의 QPS를 목표로 하는 경우에는 StarRocks의 Primary Key 모델과 Routine Load가 제공하는 컬럼 단위 병렬 업데이트 특성이 메달리온 아키텍처를 가볍게 구현하는 데 잘 맞는다.
서버와 DB 위주의 단순한 구성으로도 충분한 파이프라인을 만들 수 있는 상황을 만난다면, 한 번쯤 고려해볼 만한 조합이라고 생각한다.