Two clocks
Every event carries two clocks. Event time is when something happened on a device; processing time is when the pipeline finally sees it. On a healthy network the two stay close. On a phone that drops into a tunnel, they can drift apart by minutes. A windowed aggregation keyed on event time has to decide when a window is complete, and nothing in the stream tells it for certain.The Dataflow Model paper (Akidau et al., 2015) describes this as a tradeoff between correctness, latency and cost.
A watermark is the operator’s running assertion that no events older than time W are still in flight. The simplest strategy trails the largest timestamp seen so far by a fixed bound:
// bound the disorder we are willing to wait for
WatermarkStrategy
.<ClickEvent>forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((event, ts) -> event.occurredAt())
.withIdleness(Duration.ofMinutes(1)); Late data
Anything that arrives with an event time below the current watermark is late. It is dropped, or routed to a side output, depending on configuration. Adjust the bound below to see the trade: a wider bound admits more stragglers, and every window waits that much longer before it fires.
Scatter plot of 31 events by arrival time against event time. Raising the bound d drops fewer late events but delays when the 0–30 second window fires.
No setting of d removes both costs. The rest of this post looks at strategies that move the bound per key and per partition instead of fixing it globally.