Apache Flink: Stream Processing, Windows & State Management
Apache Flink is a true streaming engine that processes events one at a time with sub-millisecond latency, fault-tolerant managed state, and powerful windowing semantics. The framework of choice for fraud detection, real-time analytics, and event-driven architectures at scale.
What is Apache Flink?
Apache Flink is an open-source, distributed stream processing framework developed at TU Berlin and now one of the most active Apache projects. Unlike Spark Structured Streaming which processes data in micro-batches, Flink processes each event individually as it arrives, achieving consistent sub-millisecond latency. Flink provides exactly-once processing guarantees through distributed snapshots (Chandy-Lamport algorithm), making it reliable for financial and mission-critical applications.
Flink's key differentiator is managed state — stateful operations (running aggregates, session tracking, pattern matching) are stored in a configurable state backend and automatically checkpointed to durable storage. If a task fails, Flink restores state from the last checkpoint and replays from the source. Flink supports two primary APIs: the DataStream API for fine-grained control and Flink SQL for declarative streaming queries.
Window Types in Flink
- Tumbling Window — fixed-size, non-overlapping windows (e.g., 1-minute buckets); every event belongs to exactly one window
- Sliding Window — fixed-size, overlapping windows (e.g., 5-minute window every 1 minute); events can belong to multiple windows
- Session Window — dynamic gap-based windows; a window closes when no event arrives within the gap timeout; ideal for user session analysis
- Global Window — single unbounded window with a custom trigger; requires explicit trigger and evictor configuration
DataStream API with Kafka Source
# PyFlink DataStream API — event-time windowed aggregation
from pyflink.datastream import StreamExecutionEnvironment
from pyflink.datastream.connectors.kafka import KafkaSource, KafkaOffsetsInitializer
from pyflink.common import WatermarkStrategy, Duration
from pyflink.common.serialization import SimpleStringSchema
from pyflink.datastream.window import TumblingEventTimeWindows
from pyflink.common.time import Time
env = StreamExecutionEnvironment.get_execution_environment()
env.set_parallelism(4)
# Kafka source with event-time watermarks
source = KafkaSource.builder() .set_bootstrap_servers("localhost:9092") .set_topics("user-events") .set_group_id("flink-consumer") .set_starting_offsets(KafkaOffsetsInitializer.earliest()) .set_value_only_deserializer(SimpleStringSchema()) .build()
watermark_strategy = WatermarkStrategy .for_bounded_out_of_orderness(Duration.of_seconds(5)) .with_timestamp_assigner(lambda event, _: extract_timestamp(event))
stream = env.from_source(source, watermark_strategy, "Kafka Source")
# Tumbling 1-minute window, keyed by user_id
result = (
stream
.map(lambda e: parse_event(e)) # (user_id, event_type, ts)
.key_by(lambda e: e[0]) # key by user_id
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.reduce(lambda a, b: (a[0], a[1], a[2] + b[2])) # sum counts
)
result.print()
env.execute("User Event Aggregation") Flink SQL Streaming Aggregations
-- Flink SQL — streaming join and windowed aggregation
-- Create Kafka source table
CREATE TABLE orders (
order_id STRING,
user_id STRING,
amount DOUBLE,
event_time TIMESTAMP(3),
WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'orders',
'properties.bootstrap.servers' = 'localhost:9092',
'format' = 'json'
);
-- Create output sink (e.g., Iceberg table)
CREATE TABLE order_summary (
window_start TIMESTAMP(3),
window_end TIMESTAMP(3),
user_id STRING,
total_amount DOUBLE,
order_count BIGINT
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'hive_catalog',
'database-name' = 'analytics'
);
-- Tumbling window aggregation (Flink SQL TVF syntax)
INSERT INTO order_summary
SELECT
window_start,
window_end,
user_id,
SUM(amount) AS total_amount,
COUNT(*) AS order_count
FROM TABLE(
TUMBLE(TABLE orders, DESCRIPTOR(event_time), INTERVAL '1' MINUTE)
)
GROUP BY window_start, window_end, user_id; Stateful Processing with KeyedProcessFunction
# Stateful processing with Flink ValueState
from pyflink.datastream import StreamExecutionEnvironment
from pyflink.datastream.functions import KeyedProcessFunction
from pyflink.datastream.state import ValueStateDescriptor
from pyflink.common.typeinfo import Types
class FraudDetector(KeyedProcessFunction):
"""Flag users with >3 transactions in 60 seconds."""
def open(self, runtime_context):
desc = ValueStateDescriptor("tx_count", Types.INT())
self.tx_count = runtime_context.get_state(desc)
def process_element(self, value, ctx):
current = self.tx_count.value() or 0
current += 1
self.tx_count.update(current)
if current > 3:
yield f"FRAUD ALERT: user {value['user_id']} tx count {current}"
# Register a cleanup timer (TTL alternative)
ctx.timer_service().register_event_time_timer(
ctx.timestamp() + 60_000 # 60 seconds
)
def on_timer(self, timestamp, ctx):
self.tx_count.clear() # reset count after window Flink vs Spark Structured Streaming vs Kafka Streams
| Feature | Apache Flink | Spark Structured Streaming | Kafka Streams |
|---|---|---|---|
| Processing model | True streaming (event-level) | Micro-batch | True streaming |
| Latency | <1ms–10ms | 100ms–seconds | <1ms–10ms |
| State backend | RocksDB / Heap | In-memory / checkpoint | RocksDB |
| Sources / sinks | Kafka, S3, JDBC, custom | Kafka, S3, Delta, custom | Kafka only |
| SQL support | Flink SQL (excellent) | Spark SQL (excellent) | None (Java/Scala DSL) |
| Deployment | Standalone / YARN / K8s | Spark cluster | Library (no cluster) |
Frequently Asked Questions
What makes Flink 'true streaming' vs Spark's micro-batch approach?▼
Spark Structured Streaming processes data in small batches (micro-batches) — it accumulates events for a configurable trigger interval (e.g., 1 second) then processes them as a batch. Latency is bounded by the trigger interval. Flink processes each event individually as soon as it arrives, with no batching delay. This makes Flink latency sub-millisecond in practice. The distinction matters for use cases like fraud detection, real-time bidding, or alerting where every millisecond counts. For analytics dashboards with 5-second refresh rates, Spark Structured Streaming is often simpler and sufficient.
What is the difference between event time and processing time in Flink?▼
Processing time is when the event arrives at the Flink operator — easy to implement but non-deterministic and cannot handle late-arriving data correctly. Event time is the timestamp embedded in the event itself (when the event actually occurred). Event time enables correct windowing even when events arrive out of order or delayed (e.g., mobile events buffered offline). Flink uses watermarks — monotonically increasing timestamps that tell the system 'all events with time <= watermark have arrived' — to advance event time and trigger windows. Event time with watermarks is the right approach for production streaming pipelines.
What are watermarks and how should I configure them?▼
A watermark is a marker in the data stream that says 'no event with timestamp earlier than this watermark will arrive.' Flink uses watermarks to decide when to close a time window and emit results. The WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(N)) strategy allows events up to N seconds late before the watermark advances. Set N too low and late events are dropped; set it too high and window latency increases by N seconds. Choose N based on your observed maximum network/processing delay. For very late events beyond N, use allowed lateness on the window to still update results after initial emission.
What is Flink state and why is it managed separately from the application?▼
Flink's managed state is stored in a configurable state backend (Heap, RocksDB) and automatically checkpointed to durable storage (HDFS, S3) at regular intervals. This decouples state from the JVM heap — RocksDB allows state far larger than available memory. When a job fails, Flink restores from the latest checkpoint, replaying only the events since that checkpoint from Kafka (or another replayable source). This gives exactly-once processing semantics without the application needing to implement recovery logic. State is also key-partitioned — each key's state lives on the operator processing that key.
When should I use Flink SQL vs the DataStream API?▼
Flink SQL is ideal for analytics-style streaming queries — windowed aggregations, streaming joins, CDC (Change Data Capture) processing. It is less code, easier to maintain, and benefits from Flink's SQL optimizer. The DataStream API gives full control for complex custom logic: machine learning inference, complex event processing (CEP), custom state machines, and operations that do not map cleanly to SQL. In practice, mix them — use Flink SQL for the transformation layer and DataStream API for custom sources, sinks, or logic that SQL cannot express.
What is Flink's savepoint and how does it differ from a checkpoint?▼
Checkpoints are automatic, periodic snapshots triggered by Flink for failure recovery. They are managed by Flink, can be overwritten, and are not intended for manual use. Savepoints are manually triggered, operator-addressable snapshots used for application upgrades, A/B testing, or migrating to a new Flink version. You can stop a job with a savepoint, deploy new application code, and restart from the savepoint — preserving all stateful context. This is critical for zero-downtime upgrades of long-running stateful streaming jobs. Savepoints use the same format as checkpoints but have stronger stability guarantees.
Related Products
on GumroadDeveloper Productivity Bundle
Stop rebuilding the same setup every project. 51 VSCode snippets, 40 Git aliases, 5 Docker Compose stacks, 5 GitHub Actions workflows, 5 README templates, and a dotfiles kit. Set up a professional dev environment in under an hour.
Buy on Gumroad →AI Prompt Engineering Toolkit
58 structured prompt templates for Claude, ChatGPT, and Gemini — organized by use case. Code Review, Debugging, Documentation, Architecture, and 10 model-specific tips. Stop writing prompts from scratch.
Buy on Gumroad →Developer Cheat Sheet Bundle
10 print-ready cheat sheets for the tools developers use every day: Git, Docker, Linux CLI, SQL, Regex, HTTP Status codes, VS Code shortcuts, Bash scripting, jq/JSON, and Markdown.
Buy on Gumroad →You Might Also Need
JSON Formatter & Validator
Format, beautify, and validate JSON online. Paste your JSON to instantly pretty-print it with 2-space, 4-space, or tab indentation. Minify JSON too. Free, runs in your browser.
Open free tool →
Regex Tester
Free regex tester. Test regular expressions against multiple strings with expected match/no-match assertions — see instant pass/fail results. Built-in presets for email, URL, IPv4, and phone. Pro: unl
Open free tool →
Base64 Encoder & Decoder
Free Base64 Encoder & Decoder. Convert text, images, and any file to Base64 and back. Supports URL-safe Base64, image data URIs, and file download from Base64. Runs 100% in your browser — no data sent
Open free tool →
More Free Tools
Related Articles
Apache Kafka for Real-Time Data Pipelines: Tutorial 2026
Apache Kafka tutorial 2026: topics, partitions, consumer groups, producers/consumers in Python, Schema Registry, Kafka Connect, exactly-once semantics, and production best practices.
Apache Spark vs Flink: Stream Processing Comparison 2026
Apache Spark vs Apache Flink 2026: architecture differences, true streaming vs micro-batch, latency, exactly-once semantics, SQL support, state management, and when to choose each.
Apache Airflow vs Prefect: Workflow Orchestration Comparison 2026
Apache Airflow vs Prefect 2026: DAG vs flow syntax, scheduling, dynamic workflows, observability, learning curve, cloud offerings, and which to choose for your data team.
Event-Driven Architecture with Kafka and Redis Streams
Build scalable event-driven systems with Kafka and Redis Streams. Event sourcing, CQRS, consumer groups, dead letter queues, and production patterns for async microservices.
Apache Kafka vs RabbitMQ vs Redis Pub/Sub vs NATS: Message Broker Comparison 2026
A comprehensive technical comparison of Apache Kafka, RabbitMQ, Redis Pub/Sub, and NATS for message broker selection in 2026 — covering throughput, latency, persistence, use cases, and Node.js code examples.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →