A real-time analytics pipeline on AWS typically combines Kinesis Data Streams for ingestion, a stream processor like Kinesis Data Analytics (Managed Flink) or Lambda for transformation, and a serving layer such as OpenSearch, DynamoDB, or Redshift for querying. The result is data that's queryable within seconds of being generated, rather than hours later via a nightly batch job.
This article walks through a concrete architecture, the trade-offs between the major service choices, and the operational details (shard counts, checkpointing, windowing, cost) that determine whether a pipeline survives production traffic. By the end, you'll have a reference design you can adapt, along with the pitfalls that typically only show up after the proof-of-concept stage.
What does a real-time analytics pipeline actually need to do?
A real-time analytics pipeline must ingest high-velocity events, process them with low latency (seconds, not hours), and expose results to dashboards or applications without losing data during failures. The core challenge is balancing latency, throughput, and cost, because optimizing for one usually degrades another.
Concretely, the pipeline needs five stages: producers (apps, IoT devices, clickstreams), an ingestion buffer that decouples producers from consumers, a processing layer that aggregates or enriches events, a storage/serving layer optimized for fast reads, and a visualization or alerting layer. On AWS, this maps cleanly to Kinesis Data Streams → Kinesis Data Analytics / Lambda → S3 or OpenSearch or DynamoDB → QuickSight or a custom dashboard. The "real-time" requirement usually means sub-minute end-to-end latency; if your use case tolerates 15-minute delays, a simpler batch-micro-batch design with Amazon Data Firehose alone may be sufficient and considerably cheaper.
Why Kinesis Data Streams is the usual ingestion choice
Kinesis Data Streams is AWS's native streaming ingestion service, and it's the default starting point for most Kinesis pipeline designs because it integrates natively with Lambda, Kinesis Data Analytics, and Firehose without extra connectors. It stores records for a configurable retention period (24 hours by default, up to 365 days) and supports multiple independent consumers reading the same stream concurrently.
A stream is divided into shards, each supporting 1 MB/sec or 1,000 records/sec on write, and 2 MB/sec on read (shared) or up to 2 MB/sec per consumer with Enhanced Fan-Out (EFO). EFO gives each registered consumer a dedicated 2 MB/sec read throughput and pushes data via HTTP/2 within about 70ms, which matters when you have multiple downstream applications (e.g., one for fraud detection, one for dashboarding) reading the same stream and competing for the shared 2 MB/sec pool.
The alternative is Amazon MSK (Managed Streaming for Kafka). Kafka has a larger ecosystem (Kafka Connect, ksqlDB, Debezium for CDC) and is the right call if you're already running Kafka on-premises or need exactly-once semantics across complex multi-topic joins. Kinesis, by contrast, requires less operational overhead — no broker patching, no partition rebalancing to reason about — at the cost of being AWS-specific and having a simpler consumer model.
| Feature | Kinesis Data Streams | Amazon MSK | Amazon Data Firehose |
|---|---|---|---|
| Management overhead | Low (fully managed) | Medium (managed brokers, you tune partitions) | Lowest (no shards to manage) |
| Latency | Seconds | Milliseconds–seconds | ~60 sec minimum buffering |
| Scaling unit | Shards | Partitions/brokers | Automatic |
| Custom processing | Via Lambda/KDA consumers | Via Kafka Streams/Flink | Limited (Lambda transform only) |
| Best fit | AWS-native streaming apps | Kafka migrations, complex topologies | Simple load-to-S3/Redshift |
Designing the processing layer: Lambda vs. Managed Flink
For stream processing, AWS Lambda suits simple, stateless, or lightly stateful transformations, while Kinesis Data Analytics for Apache Flink (now branded as Managed Service for Apache Flink) suits complex, stateful, windowed aggregations that need exactly-once guarantees and large in-memory state.
Lambda consumers poll shards in batches (or receive push-based batches via EFO) and are simple to reason about: you write a handler, it processes an array of records, and you commit a checkpoint implicitly by returning success. This works well for enrichment (looking up a user ID in DynamoDB), filtering, or fan-out to multiple destinations. The limitation is state: Lambda is inherently stateless between invocations, so computing a 5-minute sliding average across millions of keys means you need an external store (DynamoDB, ElastiCache) to hold intermediate state, which adds latency and cost per record.
Managed Flink, on the other hand, keeps state in-memory (backed by RocksDB and checkpointed to S3), making it the natural choice for windowed aggregations — tumbling windows, sliding windows, session windows — and complex event processing like detecting patterns across a sequence of events (e.g., "three failed logins followed by a password reset within 10 minutes"). Flink applications in AWS are billed per Kinesis Processing Unit (KPU), roughly equivalent to 1 vCPU + 4 GB memory, and you pay for the application continuously, not per-invocation — so for bursty, low-volume workloads, Lambda is often cheaper; for sustained high-throughput stateful processing, Flink is more efficient and avoids the external-state-lookup tax.
A third option worth mentioning: Amazon Managed Service for Apache Flink Studio lets you write interactive SQL/Python notebooks against a stream for exploration before committing to a production Flink application — useful during the design phase of a Kinesis pipeline when you're still figuring out windowing logic.
A reference architecture: clickstream analytics
Consider a concrete example: an e-commerce site needs real-time dashboards showing active users, conversion funnel drop-off, and fraud signals, updated within 10 seconds.
Ingestion. The frontend emits events (page view, add-to-cart, checkout) via a lightweight SDK to an API Gateway HTTP API, which invokes a Lambda function (or directly uses the PutRecords API) to write into a Kinesis Data Stream named clickstream-events, provisioned in on-demand mode so shard count scales automatically with traffic rather than requiring manual capacity planning.
Processing. A Managed Flink application consumes the stream, performs: - A 1-minute tumbling window to count active sessions per region. - A sliding window join against a reference stream of product prices (also in Kinesis) to compute real-time cart value. - Stateful pattern detection (Flink CEP) to flag more than 5 checkout attempts from the same IP within 60 seconds as potential fraud.
Storage and serving. Aggregated metrics are written to DynamoDB (for dashboard reads with single-digit-millisecond latency) and raw events are simultaneously delivered via Firehose (reading from the same Kinesis stream as a second consumer) into an S3 data lake partitioned by event date/hour, in Parquet format, for later batch analysis with Athena or Redshift Spectrum.
Visualization. A dashboard built on Amazon Managed Grafana or QuickSight polls DynamoDB for near-real-time metrics, while fraud alerts trigger an SNS notification routed to Slack via a subscription Lambda.
This fan-out pattern — one stream, multiple independent consumers (Flink for real-time aggregation, Firehose for the data lake, possibly a third Lambda consumer for alerting) — is one of the main reasons teams choose Kinesis over point-to-point queueing: each consumer tracks its own position in the stream independently, so a slow or failing consumer doesn't block the others.
Handling the hard parts: ordering, replay, and backpressure
Real-time pipelines fail in predictable ways, and the fixes are mostly about anticipating them before launch rather than firefighting after.
Ordering is only guaranteed within a single shard, based on the partition key you choose when writing a record. If you need all events for a given user processed in order, hash on user_id as the partition key; if a single key sends disproportionate traffic to one shard (a "hot shard"), you'll need a composite key or random suffix to spread load, since a single shard tops out at 1,000 records/sec.
Replay and reprocessing is one of Kinesis's strongest features relative to simpler queue-based systems: because records are retained for up to 365 days (with extended retention enabled, at extra cost) rather than deleted on read, you can rewind a consumer's checkpoint and reprocess historical data — essential when you discover a bug in your aggregation logic and need to recompute the last 24 hours of metrics.
Backpressure shows up as ProvisionedThroughputExceededException on writes or iterator age growth on reads. Monitor IteratorAgeMilliseconds in CloudWatch; if it climbs, your consumer can't keep pace with the producer, and you need either more shards, a faster consumer (more Lambda concurrency, or more Flink KPUs), or an upstream rate limit. A consistently growing iterator age is the single most reliable early-warning signal that a Kinesis pipeline is falling behind.
Exactly-once vs. at-least-once is a design decision, not a default. Kinesis plus Lambda is at-least-once by default (a failed batch retries, potentially causing duplicate processing), while Managed Flink with checkpointing to S3 and idempotent sinks can achieve effectively-once semantics. If your downstream aggregation isn't idempotent (e.g., incrementing a counter rather than setting a value), duplicate delivery will silently corrupt your metrics — use idempotency keys or upsert semantics in DynamoDB to guard against this.
Cost considerations
Cost in a Kinesis-based real-time analytics pipeline comes from four places: shard-hours (or on-demand throughput pricing), data processing (Lambda invocations or KPU-hours for Flink), storage (S3 and DynamoDB), and data transfer between services within the same region (typically free) versus cross-region (not).
On-demand Kinesis mode is priced per GB ingested and per GB retrieved rather than per shard-hour, which simplifies capacity planning but can cost more than well-tuned provisioned shards at sustained high volume — as a rule of thumb, if your traffic is highly variable or you're still in the design phase, start on-demand, then switch to provisioned mode once you understand your steady-state throughput (per AWS's own guidance in the Kinesis Data Streams documentation). Managed Flink's KPU-based billing runs continuously whether or not data is flowing, so it's worth right-sizing parallelism rather than over-provisioning "just in case." Firehose, by contrast, bills per GB delivered with no idle cost, making it cheap for the data-lake side of a fan-out architecture even if it adds a 60-second minimum buffering delay.
Key Takeaways
- Kinesis Data Streams is the default AWS-native ingestion layer for real-time pipelines; choose MSK instead if you need Kafka's ecosystem or are migrating an existing Kafka deployment.
- Use Lambda for stateless or lightly stateful stream processing, and Managed Service for Apache Flink for windowed aggregations, joins, and complex event pattern detection.
- A single Kinesis stream supports multiple independent consumers (fan-out), which is ideal for sending the same data simultaneously to real-time dashboards and a batch data lake.
- Partition key choice determines ordering guarantees and shard load distribution; get it wrong and you'll create hot shards or lose necessary ordering.
- Monitor IteratorAgeMilliseconds as the primary signal of consumer lag/backpressure in a Kinesis pipeline.
- Kinesis's 24-hour-to-365-day retention enables replay and reprocessing, a major advantage over fire-and-forget queueing systems.
- Design for at-least-once delivery by default; make downstream writes idempotent unless you've explicitly built exactly-once guarantees with checkpointed, stateful processing.
Frequently Asked Questions
What's the difference between Kinesis Data Streams and Amazon Data Firehose?
Kinesis Data Streams is a low-latency, customizable streaming buffer that you read from with your own consumers (Lambda, Flink, KCL applications). Firehose is a fully managed delivery service that automatically batches and loads data into destinations like S3, Redshift, or OpenSearch, with a minimum buffering interval of around 60 seconds, so it trades a bit of latency for near-zero operational effort.
How many shards do I need for my Kinesis stream?
Start by estimating peak records/sec and peak payload size in KB; each shard handles 1 MB/sec or 1,000 records/sec on write, whichever limit you hit first. If you're unsure of your traffic pattern, use on-demand mode initially, watch CloudWatch metrics for a few weeks, then move to provisioned shards sized with headroom for traffic spikes.
Can I achieve sub-second latency with a Kinesis pipeline?
Yes, but it requires specific choices: enable Enhanced Fan-Out for dedicated 2 MB/sec throughput per consumer, use Lambda or Flink rather than Firehose (which has built-in buffering delay), and keep processing logic lightweight. End-to-end latency in the low hundreds of milliseconds is achievable, though true sub-100ms systems usually move to a lower-level event bus rather than a full analytics pipeline.
Is Kinesis Data Analytics the same as Managed Service for Apache Flink?
They refer to the same underlying AWS service; "Kinesis Data Analytics for Apache Flink" was rebranded to "Amazon Managed Service for Apache Flink" as AWS expanded it to support non-Kinesis sources like MSK and Kafka. The SQL-only version of the older Kinesis Data Analytics product has been deprecated in favor of Flink-based applications.
How do I handle schema changes in a real-time pipeline without downtime?
Use a schema registry (AWS Glue Schema Registry integrates directly with Kinesis Data Streams) and version your event schemas with backward-compatible changes (adding optional fields rather than removing or renaming required ones). Deploy consumer updates before producer updates when introducing new required fields, so old consumers never receive data in a format they can't parse.
What happens to data in a Kinesis stream if a consumer goes down?
Nothing is lost as long as you're within the retention window (24 hours by default, extendable to 365 days); each consumer tracks its own checkpoint (sequence number) independently, so a restarted consumer resumes from its last committed position. This is a key advantage over systems without replay capability, where downtime can mean permanent data loss.
Should I use DynamoDB or Redshift as the serving layer for real-time dashboards?
Use DynamoDB when you need single-digit-millisecond reads for simple key-based lookups, such as "current active users per region." Use Redshift (or Redshift Serverless) when dashboard queries involve complex joins or ad hoc aggregation across large historical datasets, accepting that query latency will be seconds rather than milliseconds.
Draw this in seconds with draft1. Describe your architecture in plain English and draft1 generates an editable AWS/cloud diagram plus documentation — no dragging boxes around. Try it free.
Draw this in ~20 seconds
Describe your own version of this architecture and draft1 generates an editable draw.io diagram — boxes, arrows, labels, the lot.
Generate this diagram free ➔Free demo — no signup. Then 3 free diagrams with an account, no card.