Integration Real-Time

Streaming Integration

Real-time event-driven data movement using Kafka Streams and Apache Flink, covering exactly-once semantics, stateful processing, watermarks, and late-arriving event handling.

⏱ 12 min read

What it is

Streaming integration is the continuous, real-time movement and transformation of data records as they are produced, with millisecond-to-second latency rather than the minutes-to-hours latency of batch integration. A stream processor subscribes to one or more event streams (Kafka topics, Kinesis shards, Pub/Sub subscriptions), processes each event or micro-window of events as they arrive, and immediately produces output to downstream topics, databases, or APIs.

The major frameworks are Kafka Streams (a lightweight Java library that runs embedded in application JVMs — no separate cluster required — for Kafka-to-Kafka transformation), Apache Flink (a full stateful stream processing engine with advanced windowing, exactly-once guarantees, and unified batch/stream API), Apache Spark Structured Streaming (extends Spark's batch DataFrame API to streaming with micro-batch or continuous processing modes), Amazon Kinesis Data Analytics (managed Flink on AWS), and Google Dataflow (managed Apache Beam runner). The choice depends on whether you need a simple Kafka-to-Kafka transformation (Kafka Streams), complex stateful event processing (Flink), or tight cloud ecosystem integration.

Why it exists

Many business requirements simply cannot be satisfied by batch processing. Fraud detection must evaluate a transaction within milliseconds of it occurring, not during the next nightly batch run. Real-time recommendation systems must update a user's personalized feed seconds after they interact with content. Infrastructure monitoring must detect and alert on anomalies within seconds, not minutes. These latency requirements drive the adoption of streaming integration even though it introduces significant additional complexity compared to batch.

Streaming also enables architectural patterns that are not possible with batch: event sourcing, real-time materialized views, streaming ETL that keeps a data warehouse current within seconds of source changes, and reactive microservices architectures where services respond to domain events as they happen. The Lambda architecture (batch layer + speed layer + serving layer) was historically used to combine the accuracy of batch with the freshness of streaming, but modern Flink deployments often replace both layers with a single streaming pipeline that also handles reprocessing.

When to use

  • Fraud and anomaly detection that must react to events within milliseconds to seconds of their occurrence.
  • Real-time analytics dashboards where business users need data freshness under 60 seconds.
  • Event-driven microservices where downstream services must react immediately to domain events from upstream services.
  • Streaming ETL to keep a data warehouse or search index continuously updated without batch window delays.
  • IoT sensor data processing where high-volume, high-frequency readings must be filtered, aggregated, and acted on in real time.
  • Operational intelligence — detecting patterns across a stream of events to trigger automated actions (auto-scaling, circuit breaking, alerting).

When not to use

  • When the latency requirement is hours or days — batch processing is far simpler and more cost-effective for nightly ETL loads or monthly reporting.
  • For aggregations that require complete dataset views (e.g., "exact rank of all users by total spend this month") — streaming approximations or batch is more appropriate.
  • When exactly-once processing is essential but the destination system does not support idempotent writes — achieving exactly-once end-to-end is extremely complex without a supporting transactional sink.
  • When the engineering team lacks stream processing expertise — a poorly tuned Flink application with incorrect watermarks or unbounded state will be harder to operate than a well-designed batch alternative.

Typical architecture


  Apache Flink Stateful Streaming Pipeline:

  Sources                 Flink Operators              Sinks
  ┌──────────────┐       ┌──────────────────────────┐  ┌────────────────┐
  │ Kafka Topic  │──────▶│  Map / FlatMap           │─▶│ Kafka Topic    │
  │ orders       │       │  (transform / enrich)    │  │ enriched-orders│
  └──────────────┘       ├──────────────────────────┤  └────────────────┘
                         │  KeyBy (user_id)         │
  ┌──────────────┐       ├──────────────────────────┤  ┌────────────────┐
  │ Kafka Topic  │──────▶│  Window (5-min tumbling) │─▶│ Elasticsearch  │
  │ clickstream  │       │  Aggregate (count, sum)  │  │ (real-time     │
  └──────────────┘       ├──────────────────────────┤  │  dashboard)    │
                         │  Watermark Strategy      │  └────────────────┘
                         │  (handle late events)    │
                         ├──────────────────────────┤  ┌────────────────┐
                         │  Stateful Process        │─▶│ PostgreSQL     │
                         │  (fraud pattern detect.) │  │ (alerts table) │
                         └──────────────────────────┘  └────────────────┘
                                    │
                         ┌──────────▼──────────┐
                         │  State Backend      │
                         │  (RocksDB / JVM)    │
                         │  Checkpointed to S3 │
                         └─────────────────────┘
          

Pros and cons

Pros

  • Low latency: data is processed milliseconds after it is produced, enabling real-time applications that are impossible with batch.
  • Continuous output: downstream consumers receive a continuous stream of results rather than waiting for a batch window to complete.
  • Incremental processing: only new data is processed on each iteration; no need to re-scan historical data as in full batch runs.
  • Event-time processing: Flink's watermark mechanism correctly handles out-of-order events and late-arriving data, enabling accurate aggregations based on when events occurred rather than when they arrived.
  • Fault tolerant with exactly-once: Flink's distributed snapshots (Chandy-Lamport algorithm) provide exactly-once processing guarantees even when operators fail and restart.

Cons

  • Significantly more complex than batch: watermarks, late event handling, state management, and exactly-once semantics add substantial operational and cognitive complexity.
  • Higher infrastructure cost: stream processors run continuously, requiring always-on compute that is more expensive than on-demand batch compute.
  • State management overhead: stateful stream processors maintain state in distributed backends (RocksDB) that must be checkpointed, sized, and managed.
  • Debugging is harder: events are processed in real time; reproducing a bug requires replaying the exact event sequence from Kafka, which adds operational complexity.
  • Late event trade-offs: choosing watermark delay parameters forces a trade-off between completeness (wait longer for late events) and freshness (emit results sooner).

Implementation notes

For Kafka Streams, use the high-level DSL (KStream, KTable, GlobalKTable) for straightforward transformations and joins. Kafka Streams automatically manages state in a local RocksDB store backed by a Kafka changelog topic, providing fault tolerance and restart recovery without external state management. For joins between a stream and a reference dataset, use a GlobalKTable (which replicates the full dataset to all instances) rather than a KTable (partitioned) to avoid co-partitioning requirements. Configure commit.interval.ms and cache.max.bytes.buffering to tune the latency/throughput tradeoff.

For Apache Flink, the critical configuration is the watermark strategy. Use WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(5)) for data with occasional late events. Events arriving after the watermark has passed the event's timestamp are either dropped or routed to a side output for separate handling — configure a side output with allowedLateness(Duration.ofMinutes(1)) to capture late events for reconciliation rather than silently dropping them. Checkpoint Flink state to S3 with incremental RocksDB checkpoints every 30–60 seconds. For exactly-once end-to-end, use Kafka transactions at the source and a transactional sink (Kafka, PostgreSQL via JDBC with upsert). The Flink Kafka connector with semantic = EXACTLY_ONCE wraps Kafka's transactional producer API.

Common failure modes

  • Unbounded state growth: A Flink stateful operator accumulates keyed state without a time-to-live (TTL) configuration; after weeks of operation, the RocksDB state backend exceeds disk capacity and the job crashes.
  • Watermark stall: A single idle Kafka partition (no messages) causes Flink's watermark to stop advancing (since the minimum watermark across all partitions is used); all time-based windows freeze and downstream operators stop emitting results.
  • Checkpoint timeout cascade: Large state causes checkpoints to take longer than the checkpoint interval; Flink eventually abandons the checkpoint and fails the job, triggering a recovery from the last successful checkpoint and causing a processing gap.
  • Consumer group lag explosion: A Kafka Streams application falls behind during a traffic spike; the consumer lag grows to millions of messages; the application takes hours to catch up, during which all downstream consumers receive stale data.
  • Exactly-once broken by non-transactional sink: A Flink job uses exactly-once semantics for Kafka but writes to Elasticsearch via HTTP; Elasticsearch does not participate in the transaction and receives duplicate writes on checkpoint recovery.

Decision checklist

  • Is the latency requirement (sub-second to minutes) actually necessary, or would batch processing satisfy the business need?
  • Have you chosen a framework appropriate for the workload: Kafka Streams for Kafka-to-Kafka transforms, Flink for complex stateful aggregations?
  • Is your state backend sized appropriately and checkpointing configured to prevent both data loss on failure and checkpoint timeout?
  • Have you configured a watermark strategy and late event handling (side output) rather than silently dropping late-arriving events?
  • Are exactly-once semantics required, and does your sink support transactional writes to achieve them end-to-end?
  • Is consumer lag monitored with alerting so that a processing bottleneck is detected before it accumulates hours of unprocessed events?

Example use cases

  • Real-time fraud detection: A Flink job consumes a Kafka stream of payment transactions, maintains per-user velocity state (count and total amount per 5-minute window), and emits fraud alerts to a Kafka topic when thresholds are exceeded — latency under 200ms from transaction event to alert.
  • Streaming ETL to data warehouse: Kafka Streams reads CDC events from a Debezium topic, joins them against a product reference GlobalKTable, enriches each order event, and writes enriched records to a Kafka topic consumed by the Snowflake Kafka Connector for sub-minute DWH freshness.
  • IoT anomaly detection: An Apache Flink application processes 100,000 sensor readings per second from Kinesis, computes 30-second rolling averages per device, and triggers alerts when readings deviate more than 3σ from the baseline — enabling predictive maintenance before equipment failure.
  • Batch Integration — The alternative to streaming; understand the latency/complexity tradeoff before choosing streaming.
  • Change Data Capture — The common source for streaming integration pipelines; CDC events from Debezium feed Flink or Kafka Streams.
  • Event Streaming — The underlying messaging infrastructure (Kafka, Kinesis) that streaming integration pipelines consume.

Further reading