서울 도시데이터 플랫폼 시리즈 ① — 왜, 무엇을, 어떻게
서울 도시데이터 플랫폼 시리즈 ① — 왜, 무엇을, 어떻게
데모 버전(임시 게시). 본 글은 블로그 발행 파이프라인 검증을 위한 데모로, 본문은 추후 정식 버전으로 교체될 예정입니다. 내용/표현/스크린샷이 곧 갱신됩니다.
이 글은
seoul-citydata-platform프로젝트의 시리즈 진입글입니다. 후속편에서는 데이터 모델링, Airflow DAG 설계, 운영 트러블슈팅 등을 다룹니다.
왜 만드는가
이 프로젝트는 단순히 “또 하나의 데이터 파이프라인” 을 만드는 게 아니라, 이전 두 포트폴리오의 약점을 면접관 시각에서 정직하게 진단하고 한 번에 보강하기 위해 시작했다.
기존 포트폴리오의 약점은 4가지였다.
- A. “준실시간”이라고 라벨링했지만 실제로는 micro-batch. Kafka 가 적재 통로(Connect → S3)였고, 처리는 15분 주기 Spark batch. streaming 처리 경험은 사실상 없었다.
- B. 실데이터를 다뤄본 적이 없다. 1번은 시뮬레이터, 2번은 Kaggle. “실데이터의 더러움” 을 만져본 적 없는 사람으로 분류될 위험.
- C. 도메인 편중. 두 프로젝트 모두 유저 행동 분석.
- D. 미해결 이슈가 “예정” 으로 끝남. 멱등성(Dynamic Partition Overwrite), 작은 파일 문제(Compaction) 모두 “도입 예정” 으로 남아있었다.
그래서 이번엔 공공 실시간 API 2종 + Postgres CDC + 익명 사용자 행동 로그라는 4종 이종 소스를 Kafka 메시지 버스로 통합하고, PyFlink streaming + Spark batch + Iceberg(Lakekeeper) + dbt + GitHub Actions 로 처리·검증한다. 동시에 익명 사용자가 실제 쓸 수 있는 작은 실서비스(공개 도메인 + 동네 북마크 + Web Push 알림)도 같이 띄워서, 약점 A·B·C·D 를 한 번에 닫는다.
운영 비용은 월 $0~$2 (Oracle Cloud Always Free + Cloudflare 무료 + 공공 무료 API), 기간은 14일. Phase 1A 10일 + Phase 1B 4일 구성.
시스템 한눈에 보기
[서울 도시데이터 API] [지하철 혼잡도 API] [Postgres places] [Cloudflare Edge API]
↓ ↓ ↓ ↓
hotspot.v1 subway.v1 places.cdc.v1 user.events.v1
└────────────────┴──────────────────┴──────────────────────┘
↓
Kafka (KRaft single-node)
↓
┌──────────────────┴──────────────────┐
↓ ↓
PyFlink streaming Cloudflare Workers Cron
(Bronze → Silver → Gold) (alert sender, P1B)
↓
Iceberg + Lakekeeper REST Catalog
↓
DuckDB / dbt → Next.js + Mapbox (Cloudflare Pages)
3계층을 시각적으로 분리한다: streaming = Flink, polling = cron, batch ops = Airflow. Day 9 의 Spark batch 는 일시 기동되어 Iceberg MERGE INTO / rewrite_data_files 로 멱등성·작은파일 문제를 직접 해결하는 보조 역할이다.
핵심 의사결정 3가지
1. Kafka KRaft single-node — Redpanda 가 아닌 Kafka, 그리고 ZooKeeper 없음
왜? 베이스라인 메시지 버스 경험을 쌓는 게 1차 목표였다. Redpanda 는 운영이 더 쉽지만 자료·생태계·면접 가산이 Kafka 쪽이 압도적이다. 대신 ZooKeeper 가 빠진 KRaft 모드를 선택해 single-node 운영 부담을 줄였다. 리소스가 부족해 broker 1개로 시작하지만, 스키마 레지스트리·토픽 명세(
v1접미사)·트랜잭션 사용 패턴은 production-grade 그대로 적용한다.
2. PyFlink streaming 을 메인, Spark batch 를 보조로
왜? 약점 A(“준실시간 라벨이지만 micro-batch”)의 정면 closure. PyFlink 로 hotspot/subway/CDC 토픽을 exactly-once 로 컨슘해 Bronze → Silver → Gold 를 실시간으로 갱신하고, 데이터 신선도 P95 < 7분 을 SLO 로 측정·게시한다. Spark 를 완전히 빼지는 않았다 — Day 9 에 일시 기동해 Iceberg
MERGE INTO로 멱등성을 검증하고,rewrite_data_files로 작은 파일 문제를 해소한다(약점 D closure).
3. Iceberg + Lakekeeper REST Catalog
왜? 단일 엔진 의존을 피하면서 카탈로그를 production 스럽게 운영하기 위해서다. Hive Metastore 는 운영 부담이 크고, JdbcCatalog 는 멀티 엔진 접근에서 한계가 있다. Lakekeeper REST Catalog 는 PyFlink·Spark·DuckDB 가 모두 동일 카탈로그를 통해 같은 테이블을 보게 해주고, 권한·스냅샷 관리를 REST API 표준으로 다룰 수 있다. fallback 으로 JdbcCatalog 도 준비해, 14일 일정 안에 Lakekeeper 가 막힐 경우의 escape hatch 를 미리 정해뒀다.
다음 글에서 다룰 것
- 데이터 모델링 — Medallion(Bronze/Silver/Gold) 구조,
dim_region/dim_placeSCD2 골격,fact_hotspot_congestion_5min(seoul-citydata-platform-data-model) - Airflow DAG 설계 — 본진 4 DAG (
dbt_full_run,iceberg_maintenance,backfill_silver_from_bronze,slo_daily_report) 와 dynamic task mapping (seoul-citydata-platform-airflow) - 운영 트러블슈팅 — Lakekeeper v0.5 셋업, Day 2 producers 디버깅 (seoul-citydata-platform-troubleshooting)
이 시리즈는 면접관이 5분만에 핵심을 잡고, 30분 안에 의사결정 근거까지 따라갈 수 있도록 설계했습니다. 피드백은 댓글 또는 GitHub issue 로 주시면 감사하겠습니다.
댓글