Side by side
| Dimension | Flink | Spark Streaming |
|---|---|---|
| Default execution | Flink: continuous, record-by-record pipeline | Spark: micro-batches by default |
| Latency | Fits tight processing-latency budgets | Includes trigger scheduling and batch execution |
| Stateful logic | Keyed state, timers, and fine-grained control | Stateful SQL and APIs; constraints depend on API and version |
| Event time | Watermarks, windows, timers, and configurable late-data handling | Watermarks and windows with output-mode and query constraints |
| Recovery | Restore checkpointed state and replay input | Recover checkpointed progress and state; replay unfinished work |
| Sink correctness | Exactly-once visibility requires a compatible sink protocol | Exactly-once visibility requires a compatible sink protocol |
| Batch integration | Supports bounded and unbounded processing | Strong fit with existing Spark SQL and batch workflows |
| Operational focus | State size, checkpoints, backpressure, and rescaling | Batch duration, input lag, state growth, and recovery |
The differences that matter
The execution model changes the latency budget. Flink can pass records through operators without waiting for a micro-batch boundary. Spark Structured Streaming normally schedules work in micro-batches, so trigger delay and batch execution affect freshness. Spark also offers continuous processing for a restricted set of queries, with different guarantees; do not assume it supports the full micro-batch feature set.
State and time semantics matter more than the streaming label. Flink exposes keyed state and event-time or processing-time timers, which suit custom expiry, per-key workflows, and complex event processing. Spark supports stateful aggregations, joins, and custom stateful logic, but supported combinations and timer behavior depend on the API and version. Validate the actual query rather than claiming Spark cannot handle state.
Both systems handle out-of-order events, but a watermark is not proof that every event has arrived. Define how long to retain state, whether late events update published results, and how to reconcile events outside that policy. In Spark, output modes and watermark placement affect when results appear and when state can be removed. In Flink, window triggers and late-data handling provide additional control.
Recovery correctness is a source-to-sink property, not an engine badge. Both systems can restore state and replay durable input, but external writes must be transactional, idempotent, or deduplicated. Flink transactional sinks may delay visibility until checkpoint completion; Spark sink behavior varies, and foreachBatch requires explicit replay-safe writes. Existing expertise, connectors, and batch integration can outweigh execution-model differences when both meet the freshness target.
Choose Flink when
- The requirement calls for tight event-to-result latency, and you will validate it under load, during checkpoints, and at the sink.
- The pipeline needs substantial keyed state, custom timers, or event-driven state transitions beyond straightforward aggregations.
- Late-event policies require fine control over window firing, corrections, and separate handling of very late records.
- The team can operate long-running stateful jobs and manage checkpoint storage, backpressure, state growth, and upgrades.
Choose Spark Streaming when
- Results can arrive on a seconds-level or slower cadence, and measured micro-batch completion fits that budget.
- The organization already operates Spark and benefits from shared SQL, libraries, connectors, and operational knowledge.
- The workload is mainly streaming ETL, SQL aggregation, or enrichment feeding an analytical table or data lake.
- Historical recomputation and live processing share substantial transformation logic, and the selected APIs support both.
A worked example
Fast click signals versus dashboard aggregates
Assume an ad platform receives 200,000 click events per second. A detection service needs provisional per-campaign signals within 250 milliseconds, while an analytics dashboard allows 10 seconds of freshness. Flink is the stronger starting point for the detection path because records can update keyed state without waiting for a micro-batch. That is not a latency guarantee: sink commits, backpressure, and checkpoint behavior still need testing. Spark Structured Streaming is a reasonable dashboard choice if the team already runs Spark and batches finish within the freshness budget. Both paths need event IDs for deduplication, a late-event policy, and reconciliation against durable input before totals become billable.
In the interview
- Start with an end-to-end freshness objective, not a product preference. Separate ingestion delay, processing time, sink commit delay, and serving delay; expect questions about tail latency and failures.
- Describe the state explicitly: partition key, window length, allowed lateness, retention, and approximate bytes per active key. Expect follow-ups about hot keys and whether state fits the recovery-time target.
- Walk through a crash after an output write but before progress is committed. Explain exactly why replay will not double-count or repeat an external side effect.
- Explain overload behavior. In Flink, inspect backpressure and checkpoint health; in Spark, inspect batch duration and input lag. For both, discuss source retention, sink capacity, skew, and catch-up throughput.
Common mistakes
- Comparing Flink only with legacy Spark DStreams without identifying which Spark API and execution mode the design uses.
- Claiming Flink is always faster or Spark is only for batch. Latency and throughput depend on the query, state, connectors, resources, and sink behavior.
- Treating engine-level exactly-once state recovery as a guarantee that arbitrary database writes, HTTP requests, or notifications happen exactly once.
- Ignoring watermark policy, unbounded state, and skew. Switching engines does not fix a hot partition or an undefined policy for late events.
Where it comes up
Interview questions where choosing between Flink and Spark Streaming comes up.
- Design an ad click aggregatorThe engine choice affects windowed aggregation, late-click corrections, duplicate handling, and the gap between provisional counts and billing totals.
- Design a metrics monitoring system like DatadogFreshness targets, high-cardinality state, rollups, and overload behavior determine whether continuous processing or micro-batches fit.
- Design a top K trending systemSliding-window expiration, skewed item keys, and replay-safe ranking updates make state and execution semantics central.
- Design Google AnalyticsSessionization, late events, distinct-user state, and analytical sink integration create concrete trade-offs between the engines.
- Design Uber surge pricingLive demand and supply windows require explicit freshness, late-data, and replay policies before choosing a processing engine.
Questions people ask
Is Flink faster than Spark Streaming?
Flink's continuous execution is often a better fit for tight per-event latency requirements than Spark's default micro-batch execution. That does not establish a universal throughput or latency winner. Compare the actual query, state size, sink visibility, and behavior during recovery under representative load.
Do Flink and Spark Streaming support exactly-once processing?
Both can provide exactly-once processing guarantees in supported configurations, but the scope matters. End-to-end results require replayable input plus sink writes that coordinate with recovery or safely tolerate retries. Arbitrary external side effects do not become exactly once simply because the engine uses checkpoints.
Should I use Flink or Spark Structured Streaming for real-time analytics?
Use the required freshness and query semantics to decide. Flink is a strong candidate for continuous low-latency updates and complex stateful event processing; Spark Structured Streaming is a strong candidate for SQL-heavy pipelines where micro-batch freshness is acceptable. Existing operational expertise and connector support should break ties.