Unit 5 · 5 hrs · CSUE301 Big Data Analytics
Streaming
Analytics
Every chapter so far treated CityCourier's sixteen orders as a finished log — a file that already exists, waiting to be read. But the orders didn't arrive that way. They arrived one at a time, in real time, and someone at head office wanted answers during the rush, not after it. This chapter processes the same sixteen rows as what they actually were: a stream.
The same sixteen dots, now arriving live
A window is a question about "so far"
How do you average something that never finishes?
Section 1.3 grouped orders into fixed 300-second windows without asking why 300, or what else was possible. Section 5.1 asks that question properly: tumbling, sliding, and session windows are three different answers.
When it happened vs. when the system saw it
Hub S's 90-second outage, revisited
Section 1.6 asked what happens to orders during a partition. This asks what happens after.
Two orders placed during Hub S's outage arrive late once the connection returns. Whether that lateness corrupts an already-computed answer depends entirely on which clock the system trusted.
Milliseconds matter differently at different speeds
0.53 orders/second barely needs streaming at all
So why does this chapter matter for CityCourier specifically?
At CityCourier's real volume, a five-second micro-batch delay is invisible. The mechanics in this chapter earn their keep the moment volume rises enough that "wait five seconds" becomes noticeable — exactly the gap between a class exercise and a system that ships.
How Do You Average Something That Never Finishes?
Section 1.3 grouped orders into 300-second blocks without asking why 300, or why blocks that don't overlap. Those were choices, not the only option.
A batch job can average "everything" because everything has an end. A stream doesn't, by definition — so any aggregate over a stream has to first answer which slice of the unbounded flow it's averaging. A window is that slice, and there are three standard shapes.
Worked Example · The Same Stream, Three Ways
Tumbling (300s) vs sliding (300s, 150s step) vs session (600s gap)
same 16 orders, three groupingsSee All Three, Same Timeline
Switch the window shape, watch the groupings change
same arrival times throughoutpitfalls
- "Windows must be non-overlapping." Only tumbling windows are. Sliding windows are deliberately overlapping — that's the entire mechanism behind a smoother, more frequently updating moving-average.
- "A session's gap threshold is a universal constant." 600 seconds made sense for CityCourier's lunch-to-dinner gap. A website click-stream might use a 30-minute threshold; a heartbeat-monitoring system might use 5 seconds. The threshold is a domain judgement call, not a fixed rule.
- "Sliding windows with a shorter step always give a 'better' answer." Better freshness, not better accuracy — and more overlapping windows means more redundant computation (Section 5.1's 150s-step example reprocesses orders 5–8 in two separate window computations each).
Practice
-
With a 300s tumbling window, which single window does order #10 (Section 1.1's veracity bug, t=378) fall into?
Solution
[300,600) — 378 sits between 300 and 600. Exactly one window, since tumbling windows never overlap.
-
Using the 300s/150s sliding window scheme, list every window order #10 (t=378) appears in.
Solution
[150,450) and [300,600) both contain 378. Two windows, because sliding windows with a 150s step and 300s size overlap by exactly half their width — any event lands in exactly two consecutive windows (except near the very start or end of the stream).
-
If the dinner rush's first order arrived at t=1,000 instead of t=1,900 (a gap of 352s from the lunch rush's last order at t=648), would the 600s session threshold still split it into two sessions?
Solution
No — 352s is under the 600s threshold, so the dinner order would extend the SAME session as the lunch rush rather than starting a new one. Session boundaries are entirely about whether the gap exceeds the threshold, not about any fixed clock time.
-
Section 1.5 showed a 2-node split being less efficient than 3 nodes due to imbalance. Does a sliding window's overlapping computation create a similar kind of "wasted work," and is it avoidable the same way?
Solution
It's a related but distinct cost — sliding windows deliberately recompute overlapping regions (orders 5–8 processed twice in the worked example) as the entire point of the mechanism, not an accidental imbalance to fix. Section 1.5's imbalance was solvable by rebalancing the split; a sliding window's overlap is inherent to getting frequent updates and can only be reduced by choosing a larger step (at the cost of less frequent updates), not eliminated while keeping the same freshness.
Two Clocks, and They Disagree
Section 1.6 asked what happens to orders placed during Hub S's 90-second outage. This asks what happens once the connection comes back — and whether the system notices the difference.
Every streamed event carries (at least) two timestamps, and streaming systems that don't distinguish them get silently wrong answers under exactly the conditions Chapter 1's CAP discussion already flagged as normal.
Worked Example · Two Delayed Orders, One Boundary Crossed
Hub S loses connectivity from t=260 to t=350 (Section 1.6's 90-second partition). Orders #8 (Wrap City, event time 289) and #9 (Curry Point, event time 333) are placed locally during the outage and only reach the stream processor once Hub S reconnects at t=350.
Order #8 — the boundary crosser
Event time 289 belongs to window [0,300). Processing time 350 belongs to window [300,600). A system that windows by processing time puts it in the wrong window.
Order #9 — delayed but harmless
Event time 333 and processing time 350 both fall in [300,600). Same window either way — this delay never crosses a boundary, so it never corrupts anything.
Recomputing the delivery-time averages from Section 1.3 under each rule:
| windowing rule | window 0 | window 1 |
|---|---|---|
| event time (correct) | n=8, avg=687.8s | n=6, avg=570.0s |
| processing time (naive) | n=7, avg=670.3s | n=7, avg=604.3s |
Both numbers in every cell changed — not just for order #8's own window, but for window 1 too, since it silently gained a record that never belonged there. Nobody has to make an obvious mistake for this to happen; it happens automatically the moment a system windows by "when I saw it" instead of "when it happened," under conditions (a network hiccup) that Chapter 1 already established are routine, not exceptional.
most streaming frameworks default to event time for exactly this reason
Spark Structured Streaming, Flink, and modern Kafka Streams all support event-time windowing as a first-class option specifically because processing-time windowing quietly breaks under network delay, retries, and partition recovery — not edge cases, but the normal operating conditions of any real distributed system. Choosing processing-time windowing is occasionally the right call (when the delay itself is the thing you want to measure), but it should be a deliberate choice, not the accidental default.
pitfalls
- "Any delay corrupts the result." Order #9 proves otherwise — delay only matters when it crosses a window boundary. Section 5.3 asks exactly how a system can know, in real time, when it's safe to stop waiting for stragglers.
- "Event time is always available." It requires the source to timestamp events at creation — a phone app tagging "confirm" with a local clock reading, say. A source that doesn't provide this leaves processing time as the only option, warts included.
- "This only matters for windowed aggregates." Any operation that depends on ORDER (a session boundary, a running total, a join against another delayed stream) can be affected by which clock defines "before" and "after," not just window membership specifically.
Practice
-
If Hub S's outage instead ran from t=550 to t=640, which orders would be delayed, and would either cross a tumbling window boundary?
Solution
Orders with event time in [550,640): order #14 (t=556) and order #15 (t=602). Both have event time within [300,600) and [600,900) respectively — if both are processed once Hub S reconnects at t=640, order #15's processing time (640) still falls in its own true window [600,900), no crossing. Order #14's event time (556) is in [300,600), and if processed at t=640 that's already in [600,900) — a crossing, structurally identical to order #8's case.
-
Recompute window 1's [300,600) naive processing-time average if order #14 (delivery time 750) is the one wrongly excluded (moved to window 2) instead of order #8.
Solution
Correct window 1 (event time) is {9,10,11,12,13,14}, avg 570.0. Removing #14 leaves {9,10,11,12,13}: (600+(−60)+930+510+690)/5 = 2670/5 = 534.0. A different order crossing a different boundary shifts the average differently — the size and direction of the error depends on which specific record got misplaced.
-
A stream processor timestamps every event with processing time only, no event time at all. Can Section 5.1's tumbling windows still be computed?
Solution
Yes — they'd just be processing-time windows by definition, not a "wrong" version of event-time windows. The problem in this section isn't that processing-time windows are invalid; it's that USING processing time while BELIEVING the result reflects event time is the error. A system that's honest about which clock it's using hasn't made a mistake, even if event time would have been more meaningful for the question being asked.
-
Chapter 3 distinguished a task's retry cost from a job-wide restart. Is order #8's boundary-crossing error a "retry" problem in that sense?
Solution
No — nothing failed and nothing is being retried. Order #8 was processed exactly once, successfully, just under the wrong window assignment. This is a correctness problem in how time is interpreted, entirely orthogonal to Chapter 3's fault-tolerance mechanics, which assume the question "which window does this belong to" was already answered correctly and only worry about task completion.
How Long Do You Wait for a Straggler?
Window 0 could wait forever for a delayed order and never be wrong. It could also emit instantly and never be complete. Neither extreme ships a usable report.
A watermark is a stream processor's running, heuristic claim: "I have now seen every event with event time before T." It's a bet, not a guarantee — but it's the mechanism that lets a window ever actually close and emit a result, rather than waiting indefinitely for events that might never arrive.
Worked Example · Order #8, Two Policies
Order #8 (event time 289, processing time 350) is 50 seconds late relative to window 0's boundary at t=300.
Allowed lateness = 40s
Window 0 emits once the watermark passes t=340. Order #8 arrives at t=350 — after emission. It's dropped (or routed to a side output for manual review), and window 0's published result is n=7, avg 670.3s — deliberately incomplete, but bounded and on time.
Allowed lateness = 60s
Window 0 doesn't emit until the watermark passes t=360. Order #8 arrives at t=350 — before that. It's included, and window 0's published result is the full n=8, avg 687.8s — correct, at the cost of 20 extra seconds of latency on every window's result, not just this one.
Notice the 40s policy's n=7 result is numerically identical to Section 5.2's "naive processing-time" mistake — same number, completely different status. The naive version silently misplaced order #8 into the wrong window, believing its answer was complete. The watermark version deliberately excludes it, knows it's incomplete, and can say so.
Watch the Watermark Decide
when lateness is too extreme for any reasonable policy
Suppose a single order's event happened at t=75 (window 0) but, due to a stuck retry queue somewhere, doesn't reach the processor until t=620 — long after even a generous allowed-lateness window would have closed. No allowed-lateness setting anyone would actually configure (measured in tens of seconds, not hundreds) would still be waiting. This is the case real systems route to a side output: not silently dropped, not silently miscounted, but explicitly flagged as "arrived too late to include," so a human or a downstream correction process can decide what to do with it.
pitfalls
- "A watermark guarantees no data arrives late." It's a heuristic estimate, explicitly allowed to be wrong. The entire allowed-lateness mechanism exists because watermarks can and do underestimate how late data might still arrive.
- "Longer allowed lateness is always safer." It's safer for correctness, strictly worse for latency — every window's result is delayed by at least the allowed-lateness amount, whether or not any late data actually shows up that period.
- "Dropped-as-too-late data is the same as data loss." A well-designed pipeline routes it to a side output rather than discarding it silently — the window's real-time answer excludes it, but nothing about the underlying event itself is destroyed.
Practice
-
Under a 60s allowed-lateness policy, at what processing time would window 1 [300,600) become eligible to emit?
Solution
t = 600 + 60 = 660. The same rule applies to every window: eligible once the watermark passes the window's own end plus the allowed-lateness constant.
-
With allowed lateness = 60s, is order #9 (processing time 350, event time 333, window 1) included in window 1's result regardless?
Solution
Yes, comfortably — window 1 doesn't even become eligible to emit until t=660, and order #9 arrives at t=350, hundreds of seconds before that. This is exactly Section 5.2's point: order #9's delay never approached being a problem for any reasonable policy.
-
A team sets allowed lateness to 0 seconds, believing it gives the "most correct" result fastest. What actually happens to order #8 under this setting?
Solution
Window 0 becomes eligible to emit the instant the watermark passes t=300 — before order #8 (arriving at t=350) has any chance of inclusion, no matter what. Zero allowed lateness doesn't mean zero lateness tolerance is achieved for free; it means the window commits to whatever it has the moment the clock hits the boundary, guaranteeing any delayed data is excluded.
-
Connect this to Section 4.3's cache eviction: is "deciding a window is closed" the same kind of bet as "deciding to evict the least-recently-used cache entry"?
Solution
Structurally similar, different stakes. Both are heuristic decisions made without complete information (recency as a proxy for future use; watermark progress as a proxy for "no more data coming") that can turn out wrong in hindsight. The difference is recoverability: an evicted cache entry can simply be recomputed via lineage with no correctness impact (Section 3.6). A window that emitted too early has already published a number someone may have acted on — correcting it means either a retraction or living with the error, a strictly costlier kind of "wrong bet."
Between the Hub and the Processor
Every order this chapter has windowed, delayed, and watermarked had to travel from a hub's till to a stream processor somehow. Something durable has to sit in between.
A message broker like Kafka decouples producers of events from consumers of them: hubs publish orders without knowing who's listening, and the stream processor reads them without knowing (or caring) which hub sent which. The unit of organisation is a topic — and every topic is split into partitions for exactly the same reason Chapter 2 split files into blocks: parallelism.
Worked Example · The "orders" Topic, Partitioned by Hub
3 partitions, 3 consumers, no overlap
16 orders · partitioned by huba topic is a log, not a queue
A traditional message queue deletes a message once consumed. Kafka's topic keeps every message for a configured retention period (or forever) — a NEW consumer group can start reading from the very beginning of the "orders" topic and get the identical 16 events, even though the original consumer group already processed them days ago. This replayability is exactly what makes Section 5.6's exactly-once story possible: if processing goes wrong, nothing was destroyed by reading it.
pitfalls
- "Kafka guarantees events are processed in the order they were sent." Only within one partition. Order #8 (Hub S) and order #4 (Hub E) have no ordering guarantee relative to each other at all — they're in different partitions, read by different consumers, on independent schedules.
- "More consumers in the group always means more throughput." Only up to the partition count. A 3-partition topic caps useful parallelism at 3 consumers, identical to Section 2.3's ring having exactly as many owners as nodes on it.
- "Partitioning by hub is the only sensible choice." It was the right choice for hub-scoped consumers here, the same way Section 2.6 showed partitioning key should match the dominant access pattern. A system that mostly needs per-restaurant throughput might partition by restaurant instead, with entirely different parallelism characteristics.
Practice
-
If the "orders" topic had 5 partitions instead of 3, keyed by restaurant instead of hub, how many orders would each partition hold (Section 3.2's restaurant counts)?
Solution
Curry Point: 4. Momo Hut: 3. Wrap City: 3. Sushi Go: 3. Pizza Barn: 3 — five partitions of 4,3,3,3,3, matching Section 3.2's MapReduce count-per-restaurant results exactly, since both are grouping the same 16 rows by the same key.
-
A consumer in the group crashes and restarts. Are the events in its assigned partition lost?
Solution
No — the partition itself is a durable, replicated log (Kafka partitions are typically replicated across brokers, the same durability principle as Section 2.1's HDFS blocks). The restarted consumer resumes from its last committed offset in that partition; nothing about the consumer failing deletes anything from the log itself.
-
Two separate consumer groups both subscribe to the "orders" topic — one computing live revenue, one archiving to cold storage. Does the revenue consumer's processing speed affect what the archiving consumer sees?
Solution
No — separate consumer groups track their own offsets independently against the same durable log. Kafka's log-not-queue design (this section's note) means one group's read speed or backlog has zero effect on any other group's ability to read the identical events from the beginning.
-
Section 2.3 showed that hash-of-order-id partitioning scatters a single hub's rows across every storage node. If "orders" were instead partitioned by hash-of-order-id rather than by hub, would a consumer assigned to "Hub E's data" even be a coherent idea?
Solution
No — exactly Section 2.3's lesson, replayed at the streaming layer. Hash-of-order-id partitioning has no relationship to hub, so Hub E's orders would be scattered across all 3 partitions; no single consumer could claim "Hub E's stream" without reading and filtering every partition, the same 3-nodes-instead-of-1 cost Section 2.6 measured for storage.
Chop It Small, or Never Chop It At All
Two frameworks, two answers to the same question: Spark Structured Streaming processes the order stream in small time-boxed chunks. Flink processes each order the instant it lands.
Spark Structured Streaming's engine is fundamentally the same batch engine Chapter 3 described: every micro-batch is a genuine, small Spark job, complete with its own ApplicationMaster negotiation (Section 3.1) and DAG scheduling (Section 3.5), just triggered automatically on a timer instead of by a person running a script. Flink was built the other way around: continuous processing is the native model, and a "batch" is just the special case of a stream that happens to end.
Worked Example · The Same Tumbling Window, Two Engines
Spark Structured Streaming
Configured with a 10-second trigger interval, it launches a fresh micro-batch job roughly 30 times over the 300-second window, each one a real, if tiny, Spark job that reads whatever arrived in the last 10 seconds and updates the running window aggregate. By the time the window closes, the answer has been recomputed roughly 30 times, each time a little more complete.
Flink
Each of the window's orders updates the running aggregate the instant it's processed — 8 individual updates for window 0, not 30 batch re-runs. The window's state is continuously current; there's no "next micro-batch" to wait for.
Both approaches produce the identical final answer for a completed window. They differ in how current the in-progress answer is at any given moment before the window closes — and in how much scheduling overhead (Section 3.1's container negotiation, repeated for every micro-batch) the system pays along the way.
this is Section 4.1's memory-vs-disk argument, one layer up
Micro-batching pays real, repeated coordination overhead — each batch is a small job with its own scheduling cost, the streaming equivalent of Section 3.5's "chained MapReduce jobs" penalty, just far cheaper per instance. True streaming avoids re-paying that cost per event, the same "avoid the repeated handoff tax" logic Section 4.1 applied to disk versus memory, now applied to job-launch overhead versus a continuously running pipeline.
pitfalls
- "Micro-batch means slow, full stop." Seconds of latency is still "real-time" for most business dashboards. The distinction matters enormously for fraud detection or algorithmic trading, and barely at all for an hourly sales summary.
- "True streaming has zero latency." Tens of milliseconds is dramatically lower than seconds, not zero — every hop still costs something, exactly Section 4.1's point about memory access not being instantaneous either, just much faster than the alternative.
- "A framework is permanently one or the other." Spark added an experimental continuous-processing mode specifically to close this gap for latency-sensitive queries; the micro-batch-vs-continuous choice is increasingly a per-query configuration, not a permanent architectural commitment to one camp.
Practice
-
If the micro-batch trigger interval were shortened from 10 seconds to 1 second, does Spark's architecture become identical to Flink's?
Solution
No — it becomes 10× more micro-batches, each still a small discrete job with its own scheduling overhead, just more frequent. Shrinking the interval narrows the latency gap but doesn't change the fundamental "many small batch jobs" architecture into "one continuous pipeline."
-
A dashboard needs to update no faster than once every 5 minutes. Does this section's latency comparison matter for choosing a framework here?
Solution
Barely — both Spark's seconds-scale micro-batch latency and Flink's tens-of-milliseconds are far below the 5-minute requirement. Framework choice here would more reasonably turn on other factors (ecosystem, existing skills, operational familiarity) than on this section's latency numbers.
-
Section 5.4 noted Kafka partitions cap useful consumer parallelism. Does that ceiling apply differently to a Spark micro-batch job versus a Flink streaming job reading the same topic?
Solution
Same ceiling either way — the partition count bounds how many parallel readers can exist regardless of what happens after reading. A Spark micro-batch job's tasks and a Flink job's parallel operator instances both ultimately map to Kafka partitions as the unit of read parallelism, exactly Section 5.4's rule, independent of which processing architecture consumes them.
-
Connect this to Section 3.6: does a failed micro-batch job get retried the same bounded way a MapReduce task does?
Solution
Yes — a failed micro-batch is a failed small Spark job, and Section 3.1–3.6's ApplicationMaster-and-task machinery applies to it exactly as it would to any other Spark job. A true-streaming system like Flink instead relies on periodic checkpoints of its continuously running state, a different mechanism aimed at the same goal: bounded recovery cost after a failure, not a full restart from the beginning of the stream.
The Same Order, Counted Twice
A consumer processes order #8, updates Hub S's running revenue total, then crashes before committing its offset. Kafka's default behaviour hands that same order to the next consumer — on purpose.
Section 5.4 established Kafka's default as at-least-once delivery: a consumer commits its offset after processing, so a crash between "processed" and "committed" means the same message gets redelivered. This is a deliberate trade, not an oversight — the alternative, committing before processing, risks silently losing a message if the crash happens the other way round.
Worked Example · Double-Counted, Then Fixed
Order #8 arrives twice. Does Hub S's revenue notice?
₹275, Wrap City, at-least-once redeliverythis is Section 1.6's duplicate-order scenario, from the inside
Section 1.6 described Hub S accepting an order locally during a network partition, risking a duplicate if the same order was also placed through another channel — framed then as a CAP-driven application concern to reconcile after the fact. This section is the identical shape of problem at the infrastructure layer: a message-delivery guarantee that can hand the same event to a consumer twice, needing the exact same fix — something keyed and idempotent, so a duplicate arrival is a no-op rather than a second event.
pitfalls
- "Exactly-once means Kafka delivers the message exactly once." It doesn't, and can't, without additional machinery — redelivery under at-least-once is the mechanism working as designed. "Exactly-once" describes the observable EFFECT of processing, achieved by making replay harmless.
- "Idempotency is a property Kafka provides automatically." It has to be designed into the processing logic — keyed by a stable identifier (order ID here), expressed as a set/overwrite rather than an increment. Kafka's transactional APIs can help coordinate this, but the idempotent design itself is the application's responsibility.
- "At-least-once is just a bug waiting to happen." It's the correct, deliberate choice whenever losing a message is worse than occasionally processing one twice — revenue counting (this section) is a case where duplication is fixable and loss isn't, which is exactly why at-least-once plus idempotent processing is the standard combination, not a workaround.
Practice
-
A consumer counts orders (not revenue) using "increment a counter by 1 per message." Is this operation idempotent under redelivery?
Solution
No — incrementing by 1 for every delivery double-counts a redelivered message exactly like the naive revenue example. Making it idempotent requires the same fix: key by order ID (e.g., "has this order ID already been counted?") rather than blindly incrementing on every message received.
-
Section 5.3's watermark-based window emission already published window 0's result. If order #8 is later redelivered due to an at-least-once retry, does idempotent processing fix the fact that the window already closed?
Solution
No — these are two separate problems. Idempotency prevents order #8 from being double-counted if it's redelivered; it does nothing about whether order #8 was ever included in the right window in the first place. A late arrival after a window has closed still needs Section 5.3's late-data policy (drop, side-output, or retract), regardless of how cleanly the delivery layer handles duplicates.
-
Would switching Kafka to at-most-once delivery (commit before processing) have avoided this section's double-counting problem?
Solution
Yes, but by trading it for the opposite failure: a crash between committing and processing would now silently lose order #8 entirely, with no retry to recover it. At-most-once avoids duplication by accepting loss; the worked example's fix (idempotent processing under at-least-once) avoids both.
-
Chapter 3 distinguished a bounded task retry from a full job restart. Is order #8's redelivery here the streaming equivalent of a "task retry," in the same bounded sense?
Solution
Yes — exactly one message gets reprocessed, not the whole stream from the beginning. Kafka's offset-based redelivery is bounded to whatever wasn't committed, the streaming analogue of Section 3.6's bounded task retry: both systems retry the smallest unit of work that might have been lost, not everything that came before it.
Chapter 5, One Page
5.1 · Windowing
Tumbling fixed, no overlap · Sliding fixed, overlapping · Session gap-defined, variable size
Each answers a different question about the same stream
5.2 · Event vs Processing Time
Event time = when it happened · processing time = when the system saw it
Delay only corrupts results when it crosses a window boundary
5.3 · Watermarks
"All events before T have likely been seen" — a heuristic, not a guarantee
Allowed lateness trades latency against completeness
Extreme lateness → side output, not silent loss
5.4 · Kafka
Topic = durable log, not a queue · partition = unit of parallelism
Order guaranteed within a partition only · consumers > partitions = idle consumers
5.5 · Micro-Batch vs Streaming
Spark: many small batch jobs, ~100ms–s latency · Flink: continuous, ~10s of ms
Same "avoid repeated handoff cost" logic as Ch4's memory-vs-disk argument
5.6 · Exactly-Once
Exactly-once = an EFFECT guarantee, not a delivery guarantee
At-least-once (default) + idempotent, keyed processing = safe under replay
At-most-once trades duplication risk for loss risk
Mixed Review
Eight questions, deliberately out of section order.
- An event's timestamp is set by the stream processor at the moment it's read, not by the source device. Is this event time or processing time?
Solution
Processing time — event time requires the timestamp to reflect when the thing actually happened at its source, not when the system happened to observe it.
- A Kafka topic has 4 partitions. A consumer group has 6 consumers. How many sit idle?
Solution
2 — each partition is read by exactly one consumer in a group at a time, so only 4 of the 6 consumers can be doing anything at all.
- A sliding window has size 10 minutes and step 10 minutes. Is this actually a sliding window, or something else?
Solution
It's functionally a tumbling window — when step equals size, there's no overlap between consecutive windows, which is the defining property of tumbling, not sliding. Sliding specifically requires the step to be smaller than the size.
- A window's watermark passes its close threshold and the window emits a result. Three seconds later, a legitimately late event for that window arrives. What are a system's realistic options?
Solution
Drop it, route it to a side output for separate handling, or issue a retraction that corrects the already-published result. Silently and invisibly folding it into a different window (Section 5.2's naive-processing-time mistake) is not a real option, since it produces a specific, silent kind of wrong answer.
- A payment-processing system chooses at-most-once delivery for a "send confirmation email" step. What failure mode does this accept, and why might that be the right call here?
Solution
It accepts that a confirmation email might occasionally never be sent (silent loss) rather than risk sending the same email twice. For a low-stakes notification, an occasional missed email is often more tolerable than annoying or confusing a customer with duplicates — a reasonable trade in a way it would NOT be for the payment charge itself.
- Spark Structured Streaming's micro-batch architecture is described in this chapter as reusing Chapter 3's machinery. Which specific Chapter 3 concept does each micro-batch correspond to?
Solution
A single Spark job — complete with its own ApplicationMaster negotiation (Section 3.1) and DAG scheduling (Section 3.5), just triggered automatically on a timer rather than by a person.
- A session window's gap threshold is set far too low for the actual data pattern. What's the likely symptom?
Solution
Far too many sessions — ordinary pauses between related events (that should belong to one session) would exceed the threshold and incorrectly split a single real session into several fragments.
- Does idempotent processing, by itself, solve the event-time-vs-processing-time problem from Section 5.2?
Solution
No — they're unrelated problems. Idempotency ensures a redelivered message doesn't get double-counted; it says nothing about which window a message's timestamp should place it in. A system can be perfectly idempotent and still window entirely by the wrong clock.
If You Want the Long Version
- Streaming Systems — Akidau, Chernyak & Lax. The definitive treatment of event time, watermarks, and windowing strategies behind Sections 5.1–5.3 — the book this chapter's further-reading note in Chapter 1 was pointing toward all along.
- Designing Data-Intensive Applications — Martin Kleppmann. Its stream-processing chapter covers Kafka's log-based design (Section 5.4) and exactly-once semantics (Section 5.6) with more depth on the underlying replication mechanics.
- Spark: The Definitive Guide — Chambers & Zaharia. Covers Structured Streaming's micro-batch model (Section 5.5) as an extension of the same DAG engine Chapter 3 and Chapter 4 already introduced.
Chapter 5 of 7 · CSUE301 Big Data Analytics · builds on Chapter 1's CAP partition scenario (Section 1.6) and Chapter 3's fault tolerance (Section 3.6).
Next → Chapter 6, Scalable Machine Learning — Big Data.