🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

Kinesis Data Analytics for Data Engineers

AWS Data EngineeringReal-time Analytics with KDA⭐ Premium

Advertisement

Kinesis Data Analytics for Data Engineers

SQL and Apache Flink Applications on Managed Streams for Real-time Analytics

15 min readIntermediate

Why This Matters

Kinesis Data Analytics (KDA) is the go-to service for real-time stream processing on AWS. It enables sub-second analytics on streaming data using standard SQL or Apache Flink. Understanding KDA architecture, windowed analytics, and Flink state management is critical for building production-grade streaming pipelines that handle millions of events per second with exactly-once guarantees. KDA eliminates the operational burden of managing streaming infrastructure while providing enterprise-grade reliability.


KDA Architecture

KDA Streaming ArchitectureKinesis DataStreamsIngestKDA ApplicationSQL EngineStandard SQLFlink RuntimeJava / ScalaOutputKinesis DataFirehose / S3Window TypesTumblingSlidingSessionState ManagementCheckpointingRocksDB BackendExactly-OnceMonitoringCloudWatch MetricsFlink DashboardLog InsightsScalingAuto-scalingKPU-basedParallelismData Flow: Source Stream to In-Application Stream to SinkKinesis Source -> KDA SQL/Flink -> Window Aggregation -> Kinesis Firehose -> S3/RedshiftCheckpointing ensures fault tolerance and exactly-once processing semantics

Real-World Project Structure

Architecture Diagram
kda-streaming-project/
+-- src/
�   +-- main/
�   �   +-- java/
�   �   �   +-- FraudDetectionJob.java
�   �   �   +-- FraudDetector.java
�   �   �   +-- TransactionDeserializer.java
�   �   �   +-- AlertSerializer.java
�   �   +-- resources/
�   �       +-- flink-conf.yaml
�   +-- test/
�       +-- FraudDetectionTest.java
�       +-- WindowAggregationTest.java
+-- sql/
�   +-- create_source_stream.sql
�   +-- aggregation_pump.sql
�   +-- windowed_query.sql
�   +-- session_window.sql
+-- deploy/
�   +-- create-application.sh
�   +-- update-application.sh
�   +-- kda-template.yaml
�   +-- cfn-stack.yaml
+-- config/
�   +-- parallelism.yaml
�   +-- checkpointing.yaml
�   +-- monitoring.yaml
+-- monitoring/
    +-- cloudwatch_dashboard.json
    +-- alarms.yaml
    +-- custom_metrics.py

SQL on Streaming Data

KDA SQL allows you to write continuous SQL queries against streaming data using a familiar syntax. The service automatically manages state, handles late-arriving data, and provides results as new rows arrive.

In-Application Streams

When you create a SQL application in KDA, you work with two types of streams:

  • Source Stream - The input data stream (e.g., from Kinesis)
  • In-Application Stream - A continuously updated table that holds streaming results
CREATE OR REPLACE STREAM "source_stream" (
    "user_id" VARCHAR(64),
    "event_type" VARCHAR(32),
    "timestamp" TIMESTAMP,
    "amount" DECIMAL(10, 2)
);

CREATE OR REPLACE STREAM "aggregated_stream" (
    "user_id" VARCHAR(64),
    "total_amount" DECIMAL(10, 2),
    "event_count" INTEGER,
    "window_start" TIMESTAMP,
    "window_end" TIMESTAMP
);

CREATE OR REPLACE PUMP "aggregation_pump" AS
    INSERT INTO "aggregated_stream"
    SELECT
        "user_id",
        SUM("amount") AS "total_amount",
        COUNT(*) AS "event_count",
        STEP("source_stream". ROWTIME BY INTERVAL '5' MINUTE) AS "window_start",
        STEP("source_stream". ROWTIME BY INTERVAL '5' MINUTE) + INTERVAL '5' MINUTE AS "window_end"
    FROM "source_stream"
    GROUP BY
        "user_id",
        STEP("source_stream". ROWTIME BY INTERVAL '5' MINUTE)
    HAVING SUM("amount") > 100;

Key SQL Concepts

ConceptDescriptionExample
STREAMUnbounded, append-only dataSensor readings, logs
TABLEBounded, up-to-date snapshotCurrent user session
PUMPContinuous query operatorWrites results to stream
MATERIALIZED VIEWPre-computed aggregationReal-time dashboard feed
ROWTIMEEvent-time timestampTime-based windowing
STEPCreates time-based windowsSTEP(ts BY INTERVAL '1' MINUTE)

Windowed Analytics

Windowing is essential for performing aggregations over bounded subsets of unbounded streaming data. KDA supports three primary window types.

Window Types

Window TypeBehaviorBest For
TumblingFixed, non-overlapping, contiguousCount per minute, hourly aggregates
SlidingFixed size, overlapping intervalsMoving averages, trend analysis
SessionDynamic, based on activity gapsUser session analytics

Window Throughput Formula

Architecture Diagram
Throughput = Records Per Window / Window Duration
Processing Rate = Input Rate x Parallelism x KPU Factor
Effective Throughput = min(Input Rate, Processing Rate) x (1 - Error Rate)

SQL Window Syntax

-- Tumbling window: 5-minute non-overlapping buckets
SELECT
    "user_id",
    SUM("amount") AS "total",
    WINDOW_START,
    WINDOW_END
FROM TABLE(
    TUMBLE(TABLE "source_stream", DESCRIPTOR("event_time"), INTERVAL '5' MINUTE)
)
GROUP BY "user_id", WINDOW_START, WINDOW_END;

-- Sliding window: 10-minute window, advancing every 2 minutes
SELECT
    "sensor_id",
    AVG("temperature") AS "avg_temp",
    MIN("temperature") AS "min_temp",
    MAX("temperature") AS "max_temp"
FROM TABLE(
    HOP(TABLE "sensor_stream", DESCRIPTOR("reading_time"),
        INTERVAL '2' MINUTE, INTERVAL '10' MINUTE)
)
GROUP BY "sensor_id", WINDOW_START, WINDOW_END;

-- Session window: closes after 30 minutes of inactivity
SELECT
    "user_id",
    COUNT(*) AS "page_views",
    MIN("event_time") AS "session_start",
    MAX("event_time") AS "session_end"
FROM TABLE(
    SESSION(TABLE "click_stream", DESCRIPTOR("event_time"), INTERVAL '30' MINUTE)
)
GROUP BY "user_id";

Apache Flink on KDA

KDA provides a fully managed Apache Flink runtime for building complex streaming applications in Java or Scala.

Flink Application Structure

public class FraudDetectionJob {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env =
            StreamExecutionEnvironment.getExecutionEnvironment();

        env.enableCheckpointing(60000);
        env.getCheckpointConfig().setCheckpointingMode(
            CheckpointingMode.EXACTLY_ONCE
        );

        DataStream<Transaction> transactions = env.addSource(
            FlinkKinesisConsumer.<Transaction>builder()
                .setArn("arn:aws:kinesis:us-east-1:123456:stream/transactions")
                .setDeserializationSchema(new TransactionDeserializer())
                .build()
        );

        DataStream<FraudAlert> alerts = transactions
            .keyBy(Transaction::getUserId)
            .process(new FraudDetector())
            .name("fraud-detection")
            .uid("fraud-detector-001");

        alerts.addSink(
            FlinkKinesisProducer.<FraudAlert>builder()
                .setSerializationSchema(new FraudAlertSerializer())
                .setStream("fraud-alerts")
                .build()
        );

        env.execute("Fraud Detection Job");
    }
}

Flink State Management

public class FraudDetector
    extends KeyedProcessFunction<String, Transaction, FraudAlert> {

    private ValueState<Double> totalAmount;
    private ValueState<Long> transactionCount;
    private ValueState<Long> lastTransactionTime;

    @Override
    public void open(Configuration parameters) {
        totalAmount = getRuntimeContext().getState(
            new ValueStateDescriptor<>("total-amount", Double.class)
        );
        transactionCount = getRuntimeContext().getState(
            new ValueStateDescriptor<>("tx-count", Long.class)
        );
        lastTransactionTime = getRuntimeContext().getState(
            new ValueStateDescriptor<>("last-tx-time", Long.class)
        );
    }

    @Override
    public void processElement(
            Transaction tx, Context ctx, Collector<FraudAlert> out)
            throws Exception {

        Double currentTotal = totalAmount.value();
        Long currentCount = transactionCount.value();
        Long lastTime = lastTransactionTime.value();

        if (currentTotal == null) currentTotal = 0.0;
        if (currentCount == null) currentCount = 0L;
        if (lastTime == null) lastTime = 0L;

        long now = tx.getTimestamp();
        long timeSinceLastTx = now - lastTime;

        totalAmount.update(currentTotal + tx.getAmount());
        transactionCount.update(currentCount + 1);
        lastTransactionTime.update(now);

        if (currentCount >= 4 &&
            timeSinceLastTx < 60000 &&
            (currentTotal + tx.getAmount()) > 500) {

            out.collect(new FraudAlert(
                tx.getUserId(),
                "RAPID_HIGH_VALUE_TRANSACTIONS",
                currentTotal + tx.getAmount(),
                now
            ));
        }

        ctx.timerService().registerProcessingTimeTimer(now + 60000);
    }

    @Override
    public void onTimer(long timestamp, OnTimerContext ctx,
            Collector<FraudAlert> out) {
        totalAmount.clear();
        transactionCount.clear();
        lastTransactionTime.clear();
    }
}

Comparison: SQL vs Flink on KDA

AspectSQL ApplicationsFlink Applications
LanguageStandard SQLJava / Scala
ComplexitySimple to moderateComplex event processing
Learning CurveLow (SQL knowledge)Moderate to high
State ManagementAutomaticManual (full control)
Custom LogicLimited to SQL functionsUnlimited
LatencySub-secondSub-second
Best ForDashboards, alerts, aggregationsPattern matching, ML inference
CostLower (less compute)Higher (more resources)

Performance Considerations

MetricDescriptionThreshold
kinesis_stream_records_readRecords read per secondVaries by workload
kinesis_stream_read_bytesBytes read per second< 2 MB/s per shard
flink_taskmanager_job_task_uptimeTask uptime in ms> 0
flink_jobmanager_job_uptimeJob uptime in ms> 0
kinesis_analytics_cpu_utilizationCPU utilization %< 80%
kinesis_analytics_heap_usedJVM heap usage< 80% of max
kinesis_analytics_number_of_uptimeApplication uptimeExpected continuous
Checkpoint DurationTime to complete checkpoint< 60 seconds

Security Considerations

ConcernImplementation
Encryption at RestS3 SSE-KMS for application code
Encryption in TransitTLS 1.2+ for Kinesis connections
AuthenticationIAM roles for KDA, Kinesis, S3 access
Network IsolationVPC endpoints, private subnets
Audit LoggingCloudTrail for all API calls
Secrets ManagementReference Secrets Manager in configs
Access ControlsIAM policies with least-privilege
Data RetentionConfigure stream retention periods

Interview Questions and Answers

Q1: What is Kinesis Data Analytics and when should you use it?

Answer: KDA is a fully managed serverless service for analyzing streaming data in real-time using SQL or Apache Flink. Use it when you need continuous, low-latency analytics on streaming data such as real-time dashboards, fraud detection, IoT monitoring, clickstream analysis, or any use case requiring sub-second insights from streaming sources. It is cost-effective for moderate throughput and eliminates infrastructure management overhead.

Q2: Explain the difference between KDA SQL and KDA Flink.

Answer: KDA SQL provides standard SQL syntax for streaming analytics - ideal for aggregations, filters, and windowed queries without writing code. KDA Flink supports Java/Scala applications for complex event processing, stateful computation, pattern matching, and custom logic. SQL is simpler and cheaper; Flink offers full programmatic control and advanced capabilities like CEP and custom operators.

Q3: What are the three window types in KDA and when would you use each?

Answer: Tumbling windows are fixed, non-overlapping time intervals (e.g., total sales per 5 minutes) - use for periodic aggregations. Sliding windows are fixed-size, overlapping intervals (e.g., average temperature over the last 10 minutes, updated every minute) - use for moving averages and trend analysis. Session windows are dynamic, based on activity gaps (e.g., user sessions with 30-minute inactivity timeout) - use for behavioral analytics.

Q4: How does KDA handle late-arriving data?

Answer: KDA handles late-arriving data through event-time processing and watermarks. You can define tolerance periods using WITHIN clauses in SQL or watermarks in Flink. Late data beyond the tolerance is either dropped or processed with allowed lateness. In Flink, you can use allowedLateness() and side outputs for late data handling, ensuring accurate windowed computations even with out-of-order events.

Q5: What is an In-Application Stream in KDA SQL?

Answer: An In-Application Stream is a continuously updated, append-only relation within a KDA SQL application. It represents the results of a continuous query and updates automatically as new input arrives. You create streams with CREATE OR REPLACE STREAM and populate them with PUMP statements. In-application streams are the core abstraction for chaining transformations in KDA SQL.

Q6: How do you ensure exactly-once processing in KDA Flink?

Answer: Exactly-once processing in KDA Flink is achieved through: (1) Checkpointing - periodic state snapshots saved to S3; (2) Barrier alignment - ensures all operators process the same checkpoint; (3) State backends - RocksDB stores state efficiently; (4) Sink commits - two-phase commit protocols for external systems. Configure with CheckpointingMode.EXACTLY_ONCE and appropriate intervals (typically 30-60 seconds).

Q7: What are some common KDA metrics to monitor?

Answer: Key metrics include: kinesis_stream_records_read (input throughput), kinesis_analytics_cpu_utilization (CPU pressure), kinesis_analytics_heap_used (memory usage), flink_taskmanager_job_task_uptime (task health), kinesis_analytics_uptime (application availability), and checkpoint metrics (duration and size for health assessment). Set up CloudWatch alarms for critical thresholds.

Q8: How does autoscaling work in KDA?

Answer: KDA autoscaling automatically adjusts parallelism based on workload. When enabled, it monitors throughput and processing latency, then increases or decreases parallelism (within configured min/max bounds). This uses KPU-based scaling - you pay for the KPU-hours consumed. Autoscaling is most effective with Flink applications where state can be redistributed during rescaling. Start with lower parallelism and let autoscaling handle peak loads.


Common Pitfalls

PitfallImpactSolution
Using SQL for complex event processingLimited functionalityUse Flink for CEP patterns
Not configuring checkpointingData loss on failureEnable with 30-60s intervals
Ignoring late-arriving dataInaccurate aggregationsSet watermarks and tolerance
Over-provisioning parallelismUnnecessary costStart low, enable autoscaling
Not monitoring heap usageOOM crashesTrack heap metrics, tune memory
Hardcoded credentialsSecurity riskUse Secrets Manager references
Not using exactly-onceData duplicationEnable checkpointing with EXACTLY_ONCE
Ignoring KPU costsBudget overrunsMonitor KPU-hours consumed


See Also

Additional Deep Dive: KDA Application Management

Application Lifecycle Management

#!/bin/bash
# Create KDA SQL application

APPLICATION_NAME=$1
INPUT_STREAM=$2
OUTPUT_STREAM=$3

aws kinesisanalyticsv2 create-application \
    --application-name "${APPLICATION_NAME}" \
    --runtime-environment FLINK-1_18 \
    --service-execution-role "arn:aws:iam::123456789012:role/kda-role" \
    --application-configuration "{
        \"ApplicationCodeConfiguration\": {
            \"CodeContent\": {
                \"S3ContentLocation\": {
                    \"BucketARN\": \"arn:aws:s3:::my-kda-code\",
                    \"FileKey\": \"app.jar\"
                }
            },
            \"CodeContentType\": \"ZIPFILE\"
        },
        \"FlinkApplicationConfiguration\": {
            \"ParallelismConfiguration\": {
                \"AutoScalingEnabled\": true,
                \"Parallelism\": 4,
                \"ParallelismPerKPU\": 1,
                \"ConfigurationType\": \"CUSTOM\"
            },
            \"CheckpointConfiguration\": {
                \"CheckpointingEnabled\": true,
                \"CheckpointIntervalInMillis\": 60000,
                \"ConfigurationType\": \"CUSTOM\"
            }
        }
    }"

Flink Application Deployment

#!/bin/bash
# Deploy Flink application to KDA

APPLICATION_NAME=$1
JAR_PATH=$2

# Update application code
aws kinesisanalyticsv2 update-application \
    --application-name "${APPLICATION_NAME}" \
    --current-application-version-id $(aws kinesisanalyticsv2 describe-application \
        --application-name "${APPLICATION_NAME}" \
        --query 'ApplicationDetail.ApplicationVersionId' \
        --output text) \
    --application-configuration-update "{
        \"ApplicationCodeConfigurationUpdate\": {
            \"CodeContentUpdate\": {
                \"S3ContentLocationUpdate\": {
                    \"BucketARN\": \"arn:aws:s3:::my-kda-code\",
                    \"FileKey\": \"${JAR_PATH}\"
                }
            }
        }
    }"

Monitoring and Alerting

#!/bin/bash
# Setup CloudWatch alarms for KDA

APPLICATION_NAME=$1

# CPU utilization alarm
aws cloudwatch put-metric-alarm \
    --alarm-name "${APPLICATION_NAME}-HighCPU" \
    --alarm-description "KDA application CPU high" \
    --metric-name "kinesis_analytics_cpu_utilization" \
    --namespace "AWS/KinesisAnalytics" \
    --statistic Average \
    --period 300 \
    --evaluation-periods 2 \
    --threshold 80 \
    --comparison-operator GreaterThanOrEqualToThreshold \
    --dimensions Name=Application,Value="${APPLICATION_NAME}" \
    --alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts

# Heap usage alarm
aws cloudwatch put-metric-alarm \
    --alarm-name "${APPLICATION_NAME}-HighHeap" \
    --alarm-description "KDA application heap usage high" \
    --metric-name "kinesis_analytics_heap_used" \
    --namespace "AWS/KinesisAnalytics" \
    --statistic Average \
    --period 300 \
    --evaluation-periods 2 \
    --threshold 80 \
    --comparison-operator GreaterThanOrEqualToThreshold \
    --dimensions Name=Application,Value="${APPLICATION_NAME}" \
    --alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts

Windowed Aggregation Examples

-- Complex tumbling window with multiple aggregations
SELECT
    "category",
    COUNT(*) AS "total_events",
    SUM("amount") AS "total_amount",
    AVG("amount") AS "avg_amount",
    MIN("amount") AS "min_amount",
    MAX("amount") AS "max_amount",
    COUNT(DISTINCT "user_id") AS "unique_users",
    WINDOW_START,
    WINDOW_END
FROM TABLE(
    TUMBLE(TABLE "source_stream", DESCRIPTOR("event_time"), INTERVAL '1' HOUR)
)
GROUP BY "category", WINDOW_START, WINDOW_END;

-- Sliding window for moving averages
SELECT
    "sensor_id",
    AVG("reading") AS "moving_avg",
    STDDEV("reading") AS "moving_stddev",
    COUNT(*) AS "sample_count",
    WINDOW_START,
    WINDOW_END
FROM TABLE(
    HOP(TABLE "sensor_stream", DESCRIPTOR("reading_time"),
        INTERVAL '5' MINUTE, INTERVAL '1' HOUR)
)
GROUP BY "sensor_id", WINDOW_START, WINDOW_END;

-- Session window for user activity
SELECT
    "user_id",
    COUNT(*) AS "page_views",
    COUNT(DISTINCT "page") AS "unique_pages",
    MIN("event_time") AS "session_start",
    MAX("event_time") AS "session_end",
    TIMESTAMPDIFF(MINUTE, MIN("event_time"), MAX("event_time")) AS "session_duration"
FROM TABLE(
    SESSION(TABLE "click_stream", DESCRIPTOR("event_time"), INTERVAL '30' MINUTE)
)
GROUP BY "user_id";

Error Handling in Flink

public class ErrorHandler implements ExceptionHandler<Record> {
    @Override
    public void handleException(Record record, Throwable exception) {
        // Log the error
        LOG.error("Failed to process record: {}", record, exception);

        // Send to dead letter queue
        sendToDLQ(record, exception);

        // Update error metrics
        errorCounter.inc();
    }

    private void sendToDLQ(Record record, Throwable exception) {
        // Implementation for sending to DLQ
    }
}

Application Configuration Reference

ParameterDefaultRecommendedDescription
Parallelism14-16Number of parallel tasks
ParallelismPerKPU11Tasks per KPU
CheckpointInterval6000030000-60000Checkpoint frequency
MinPauseBetweenCheckpoints500030000Minimum pause
CheckpointTimeout600000120000Checkpoint timeout
MaxConcurrentCheckpoints11-2Concurrent checkpoints
EnableUnalignedCheckpointsfalsefalseFor low latency

Data Format Support

FormatSourceSinkNotes
JSONYesYesSchema inference
CSVYesYesDelimiter configurable
AvroYesYesSchema registry
ParquetYesYesColumnar, compressed
ORCYesYesHive optimized
ProtobufYesYesBinary, schema evolution
🔒

Premium Content

Kinesis Data Analytics for Data Engineers

You've previewed the first section. Unlock this full lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
💼Interview Prep
📜Certificates
🤝Community Access

Already a member? Log in

Advertisement