• Material 깔끔한 그림자와 부드러운 모서리
  • Neo-Brutalism 두꺼운 테두리와 하드 섀도우
  • Glassmorphism 반투명 유리 효과
  • Reading 세리프 본문, 따뜻한 종이 톤, 콘텐츠 중심

서울 도시데이터 플랫폼 시리즈 ① — 왜, 무엇을, 어떻게

서울 도시데이터 플랫폼 시리즈 ① — 왜, 무엇을, 어떻게

WARNING

데모 버전(임시 게시). 본 글은 블로그 발행 파이프라인 검증을 위한 데모로, 본문은 추후 정식 버전으로 교체될 예정입니다. 내용/표현/스크린샷이 곧 갱신됩니다.

이 글은 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 그대로 적용한다.

왜? 약점 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_place SCD2 골격, 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 로 주시면 감사하겠습니다.

댓글