CASE FILE

CH.02STREAMING

Real-time Streaming Lakehouse

KAFKAFLINKICEBERGDBT
A frozen lake holds table-shaped icebergs beneath an aurora of flowing data, with a lone cabin on the shore.

THE PROBLEM

Ops and finance were running the day off dashboards built on nightly batch jobs, so every morning meeting argued about numbers that were already a day stale. The legacy full-refresh jobs could not stay: they re-read everything, they got slower as volume grew, and warehouse streaming pricing was not an option. I rebuilt the ingestion path as streaming on open table formats, and hit the classic wall early — thousands of small files from streaming writes turned queries into a crawl until compaction became part of the pipeline, not a cleanup script.

CONSTRAINTS

  • Late and out-of-order events are the norm, not the exception
  • Streaming writes create thousands of small files that murder reads
  • dbt models must run against tables that never stop moving
  • Storage and compute costs must stay flat as volume grows

DECISIONS & TRADEOFFS

FLINK over micro-batch streaming — because true event-time processing with watermarks handles late data honestly instead of faking it with window hacks

ICEBERG over proprietary warehouse tables — because open table format with snapshot isolation lets readers and stream writers coexist, and any engine can query the same data

SCHEDULED COMPACTION over write-optimized only — because I watched unbounded small files destroy read performance and object-store bills, so maintenance is part of the pipeline, not an afterthought

ARCHITECTURE

01EVENT SOURCESproducers emitcontinuously02KAFKAdurable orderedtransport03FLINK JOBSevent-time windows,watermarks04ICEBERG TABLESsnapshots,partition evolution05COMPACTIONsmall-file andmanifest06DBT MODELSincremental onstreaming tables07SERVING VIEWSfreshness inminutes

OUTCOME

Dashboards moved from daily batch to minutes-level streaming, so ops reacts to the current hour instead of yesterday, and downstream models query the same open tables instead of waiting on exports. Finance sees costs hold flat because compaction and partitioning are operationalized, not heroic. I run this on commodity object storage and the full-refresh jobs are gone.

PROOF / LINKS

PROPRIETARY WORK — THE SHAPE OF IT IS PUBLIC HERE, THE SYSTEM ITSELF IS NOT.

AT 100× SCALE

At 100x this becomes a multi-engine data platform: the same Iceberg tables serve Flink, Spark, and ad-hoc SQL, with tiered storage and per-topic freshness SLAs instead of one-size-fits-all latency.