Definition
- Eager watermark – Small or zero out-of-orderness delay, so the watermark advances quickly and windows fire with minimal latency, but slightly-delayed events are treated as late and dropped.
- Relaxed watermark – Larger out-of-orderness delay, so the watermark trails further behind, waiting longer for stragglers and giving more complete results at the cost of higher latency.
- Latency-completeness trade-off – The watermark delay is a global latency tax on every window; a larger delay catches more late events but adds end-to-end latency uniformly.
- Hybrid approach – Keep the watermark fairly eager and add allowed lateness so only windows that actually receive late data pay the extra cost.
- Choice criteria – Alerts and fraud detection lean eager; settlements, audits, and regulatory reports lean relaxed.
The National Bank of India must decide how long to hold a business minute open before declaring it closed. An eager policy is an impatient manager who closes the minute the instant the clock ticks over, so the report comes out fast, but any slip still walking through the door a few seconds late gets thrown away. A relaxed policy is a patient manager who holds the minute open for an extra ten seconds to let stragglers arrive, so the total is more accurate but the report publishes later.
Understanding the Concepts
What is an eager watermark?
An eager watermark uses a small or zero out-of-orderness delay so the watermark advances quickly, hugging the maximum observed event time. Windows fire almost immediately after the last expected event, giving the lowest possible latency.
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import java.time.Duration;
// Eager: 200ms out-of-orderness
WatermarkStrategy<Transaction> eager =
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofMillis(200))
.withTimestampAssigner(
(txn, ts) -> txn.getEventTimeMillis());
// Ultra-eager: zero (monotonous timestamps)
WatermarkStrategy<Transaction> ultraEager =
WatermarkStrategy.<Transaction>forMonotonousTimestamps()
.withTimestampAssigner(
(txn, ts) -> txn.getEventTimeMillis());
Eager (200ms): max_event_time = 10:05:00.500 watermark = 10:05:00.300 Window [10:05:00, 10:05:01) fires almost instantly Late event at 10:04:59.800 → 10:04:59.800 < 10:05:00.300 → DROPPED
What is a relaxed watermark?
A relaxed watermark uses a larger out-of-orderness delay so the watermark trails well behind the latest event. Each window waits longer before firing, capturing almost all realistically late events.
// Relaxed: 30 seconds out-of-orderness
WatermarkStrategy<Transaction> relaxed =
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofSeconds(30))
.withTimestampAssigner(
(txn, ts) -> txn.getEventTimeMillis());
Relaxed (30s): max_event_time = 10:05:30.000 watermark = 10:05:00.000 Window [10:05:00, 10:05:01) has NOT fired yet Late event at 10:05:00.500 → 10:05:00.500 > 10:05:00.000 → ACCEPTED Window fires 30 seconds later than eager approach
How are they different?
| Aspect | Eager | Relaxed |
|---|---|---|
| Out-of-orderness | 0-500ms | 10-60 seconds |
| Window firing latency | Very low | Higher |
| Late event handling | Drops more stragglers | Captures almost all |
| Memory usage | Lower (fewer open windows) | Higher (more open windows) |
| Result accuracy | May undercount | Near-complete |
| Best for | Real-time alerts, fraud detection | Settlements, regulatory reports |
// Side by side on the same stream:
// Eager: fast but incomplete
txnStream.assignTimestampsAndWatermarks(eager)
.keyBy(txn -> txn.getAccountId())
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.sum("amount"); // fires fast, may miss 1% of events
// Relaxed: slow but complete
txnStream.assignTimestampsAndWatermarks(relaxed)
.keyBy(txn -> txn.getAccountId())
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.sum("amount"); // fires 30s later, captures 99.9% of events
How do you choose between eager and relaxed?
The choice depends on whether the use case values speed or completeness. Measure the real lateness distribution of your source and match the watermark to the business need.
// Use case 1: Fraud alerting -- speed matters
// A 1-second delay in flagging a card-testing burst is unacceptable
// Missing one straggler out of hundreds does not change the alert
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofMillis(200)); // EAGER
// Use case 2: End-of-day settlement -- completeness matters
// The totals must balance to the rupee for the general ledger
// 30 seconds of extra latency is acceptable
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofSeconds(30)); // RELAXED
What is the hybrid approach?
The most powerful approach combines an eager watermark with allowed lateness and a side output. The window fires eagerly for low latency, then re-emits corrected results as late events trickle in within the allowed lateness, and the extreme tail goes to a side output.
import org.apache.flink.util.OutputTag;
import org.apache.flink.streaming.api.windowing.time.Time;
OutputTag<Transaction> lateTag = new OutputTag<>("late-txns") {};
SingleOutputStreamOperator<String> result = txnStream
.assignTimestampsAndWatermarks(
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofSeconds(2)) // fairly eager
.withTimestampAssigner(
(txn, ts) -> txn.getEventTimeMillis()))
.keyBy(txn -> txn.getAccountId())
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.allowedLateness(Time.seconds(30)) // window stays open 30s more
.sideOutputLateData(lateTag) // extreme tail captured
.apply(windowFunction);
// Benefits:
// 1. First result emits after 2s delay (eager)
// 2. Late events within 30s update the result (correction)
// 3. Very late events go to side output (never lost)
What are the cost implications?
The watermark delay is a global latency tax on every window. A large delay taxes all windows even though most may have complete data. Allowed lateness only pays the extra cost on windows that actually receive late data.
// Global tax: 30s relaxed watermark
// ALL windows wait 30 extra seconds, even ones with complete data
// Targeted cost: 2s eager + 30s allowed lateness
// Only the ~1% of windows that receive late data pay the extra cost
// The other 99% of windows fire after just 2s
What are common mistakes?
The most common mistake is using a very relaxed watermark for a use case that needs low latency. Another mistake is using an eager watermark without monitoring how many events are being dropped.
// WRONG -- relaxed watermark for real-time alerting
WatermarkStrategy.<Transaction>forBoundedOutOfOrderness(
Duration.ofMinutes(5)); // 5 minutes of latency for alerts!
// Fraud goes undetected for 5 extra minutes
// CORRECT -- eager watermark for alerts, relaxed for settlements
// Alert pipeline: Duration.ofMillis(200)
// Settlement pipeline: Duration.ofSeconds(30)
What should a senior engineer know?
Never pick the delay by guessing. Measure the real lateness distribution of the source and set the bound to cover the bulk of it. The smart move is often an eager watermark plus allowed lateness rather than a blanket large delay, because that only pays the extra waiting cost for windows that actually receive late data. Monitor dropped-late metrics to validate your choice over time.
Visual Overview
Eager vs Relaxed Watermark Spectrum ◀──────── EAGER ──────────────── RELAXED ────────▶ Duration.ofMillis(200) Duration.ofSeconds(30) ┌────────────────┐ ┌────────────────┐ │ Fast results │ │ Complete results│ │ Low latency │ │ High latency │ │ Drops ~1% │ │ Drops ~0.01% │ │ Less memory │ │ More memory │ │ Alerts, fraud │ │ Settlements │ └────────────────┘ └────────────────┘ Hybrid Approach (Best of both): ┌──────────────────────────────────────────┐ │ Eager watermark (2s) │ │ │ │ │ ▼ │ │ Window fires (speculative result) │ │ │ │ │ Late event arrives within 30s │ │ │ │ │ ▼ │ │ Window re-emits (corrected result) │ │ │ │ │ Very late event (beyond 30s) │ │ │ │ │ ▼ │ │ Side output (captured, not lost) │ └──────────────────────────────────────────┘
Key Takeaway
Eager and relaxed watermarks are two ends of a single tuning spectrum, and the dial is the out-of-orderness bound in the watermark strategy. An eager watermark uses a very small delay so windows fire fast with low latency, but slightly-delayed events are dropped. A relaxed watermark uses a larger delay so windows wait longer, capturing almost all late events at the cost of higher latency and more memory.
The choice depends on what the use case values. Real-time alerting and fraud detection lean eager because reacting in a second matters more than perfect counts. End-of-day settlements and regulatory reports lean relaxed because the numbers must be exactly right and a few extra seconds of latency is acceptable.
The most powerful approach in practice is a hybrid: keep the watermark fairly eager for low latency, add allowed lateness so late events within a grace period correct the result, and use a side output for the extreme tail. This way only the windows that actually receive late data pay the extra waiting cost, instead of taxing every window with a large watermark delay.
At the National Bank of India Rajesh ran exactly these two profiles over the same transaction stream. The fraud alerting job used an eager watermark of 200 milliseconds, while the end-of-day settlement job feeding the general ledger used a relaxed watermark of 30 seconds. He could show concretely that the eager path dropped a straggler and undercounted, while the relaxed path captured it and was complete.
Remember one sentence: The watermark delay is a global latency tax on every window, so keep it eager and use allowed lateness for corrections rather than inflating the delay for a rare straggler.
---