Cloud Architecture

Building Scalable Data Pipelines with AWS Kinesis, Glue, and Redshift

Learn to build robust, scalable data pipelines on AWS using Kinesis for real-time ingestion, Glue for serverless ETL, and Redshift for powerful analytics.

Khader Vali July 3, 2026 16 min read

Building Scalable Data Pipelines with AWS Kinesis, Glue, and Redshift

In today’s data-driven world, the ability to collect, process, and analyze vast amounts of data in a timely manner is paramount for businesses seeking competitive advantage. From real-time operational insights to strategic long-term planning, a robust data pipeline forms the backbone of any effective data strategy. Building such pipelines can be complex, requiring careful consideration of scalability, cost, performance, and maintainability.

AWS offers a suite of powerful, managed services that, when combined, provide an incredibly flexible and scalable platform for data pipeline construction. Among these, Amazon Kinesis, AWS Glue, and Amazon Redshift stand out as a formidable trio for handling real-time data ingestion, serverless Extract, Transform, Load (ETL) operations, and petabyte-scale data warehousing, respectively.

As a senior engineer, I’ve seen firsthand the challenges companies face in moving from siloed, batch-oriented data processes to integrated, real-time analytics. This article will guide you through the process of architecting and implementing a modern data pipeline on AWS using Kinesis, Glue, and Redshift. We’ll explore each service in detail, discuss their integration points, provide practical code examples, and outline best practices to ensure your data pipeline is not just functional, but also resilient, cost-effective, and future-proof.

The Imperative for Modern Data Pipelines

Traditional data warehousing often involved nightly batch jobs that processed data accumulated over a day. While sufficient for some reporting needs, this approach falls short in an era demanding instant insights. Businesses need to react to user behavior, market trends, and operational anomalies as they happen. This necessitates:

  • Real-time Ingestion: The ability to capture data streams from various sources (IoT devices, web applications, logs) with minimal latency.
  • Scalable Processing: Handling fluctuating data volumes, from megabytes to terabytes per hour, without manual intervention or performance degradation.
  • Flexible Transformation: Cleaning, enriching, and transforming raw data into a usable format for diverse analytical needs, often requiring complex logic.
  • High-Performance Analytics: Storing massive datasets and enabling lightning-fast queries for business intelligence (BI) tools, dashboards, and ad-hoc analysis.
  • Cost Efficiency: Optimizing infrastructure costs by leveraging serverless and managed services that scale with demand.

This is where the AWS ecosystem truly shines, providing managed services that address each of these requirements, allowing engineers to focus on data logic rather than infrastructure management.

Understanding the Core AWS Services in Our Pipeline

Before diving into the architecture, let’s briefly introduce the stars of our show:

Amazon Kinesis: Your Real-time Data Ingestion Layer

Amazon Kinesis is a fully managed service for processing large streams of data in real time. It’s designed to handle high throughput and low latency data ingestion, making it ideal for collecting data from thousands of diverse sources concurrently.

  • Kinesis Data Streams (KDS): The foundational component. It allows you to build custom applications that process or analyze streaming data for specialized needs. Data is organized into shards, which are units of throughput capacity. You pay for the number of shards and the data ingested.
  • Kinesis Firehose: A simpler, serverless option for delivering streaming data to destinations like Amazon S3, Amazon Redshift, Amazon OpenSearch Service, and Splunk. Firehose automatically scales to match the throughput of your data and requires no administration. It can also perform basic transformations and data format conversions (e.g., JSON to Parquet).
  • Kinesis Data Analytics: Allows you to process and analyze streaming data with SQL or Apache Flink without managing servers.

Why Kinesis? It provides unparalleled scalability and durability for real-time data ingestion. Whether it’s clickstreams, IoT sensor data, or application logs, Kinesis can reliably capture it all, acting as a buffer and ensuring no data is lost even during downstream processing delays.

AWS Glue: The Serverless ETL and Data Catalog Maestro

AWS Glue is a fully managed, serverless ETL (Extract, Transform, and Load) service that makes it easy to prepare and load your data for analytics. It’s a cornerstone for building data lakes and data warehouses on AWS.

  • AWS Glue Data Catalog: A central metadata repository that stores schema information for your data. It works across various AWS services (S3, Redshift, Athena) and acts as a unified metadata store for your data lake.
  • AWS Glue Crawlers: Automatically discover the schema and partitioning structure of your data stored in S3, JDBC data stores, and other sources, then populate the Glue Data Catalog.
  • AWS Glue Jobs: Run ETL scripts (written in Python or Apache Spark) that can read from various data sources (including S3 via the Data Catalog), transform the data, and write it to desired destinations (like S3 or Redshift). Being serverless, Glue Jobs automatically provision, manage, and scale the resources needed.

Why Glue? It eliminates the operational overhead of managing ETL servers. Its Data Catalog provides a single source of truth for metadata, simplifying data discovery and governance. Glue’s ability to auto-generate and execute Spark jobs dramatically accelerates the development of complex data transformations.

Amazon Redshift: The Petabyte-Scale Data Warehouse

Amazon Redshift is a fast, fully managed, petabyte-scale data warehouse service. It’s designed for analytical workloads and is optimized for columnar storage, massively parallel processing (MPP), and high-performance querying of large datasets.

  • Columnar Storage: Stores data in a column-oriented fashion, which significantly improves query performance for analytical workloads that often read only a subset of columns.
  • Massively Parallel Processing (MPP): Distributes data and query processing across multiple nodes in a cluster, enabling parallel execution of queries for faster results.
  • Managed Service: AWS handles hardware provisioning, software patching, backups, and replication, allowing you to focus on data analysis.

Why Redshift? For large-scale analytical querying and business intelligence, Redshift offers superior performance and cost-effectiveness compared to traditional relational databases. It integrates seamlessly with BI tools and other AWS services, making it the ideal destination for your processed analytical data.

Architecting the Pipeline: A Conceptual Overview

Let’s visualize (in words) how these services integrate to form a powerful, end-to-end data pipeline. Our goal is to ingest real-time data, transform it, and make it available for high-performance analytics.

The general flow can be described as follows:

  1. Data Producers: Your applications, IoT devices, or other sources generate events and continuously send them to Amazon Kinesis.
  2. Real-time Ingestion (Kinesis Data Streams): Kinesis Data Streams acts as a highly scalable, durable buffer, ingesting raw events as they arrive. This layer ensures data capture even under peak loads.
  3. Raw Data Landing (Kinesis Firehose to S3 or Custom Consumer to S3):
    • Option A (Simpler): A Kinesis Firehose delivery stream consumes data directly from the Kinesis Data Stream. Firehose then buffers the data, optionally transforms it (e.g., converts JSON to Parquet), and delivers it in batches to an Amazon S3 bucket, our raw data landing zone.
    • Option B (More Customization): A custom Kinesis consumer (e.g., an AWS Lambda function or an application running on EC2/ECS) reads data from the Kinesis Data Stream, performs initial lightweight processing if needed, and writes the raw events to Amazon S3.

    Amazon S3 serves as our cost-effective, highly durable, and scalable data lake. It stores the raw, immutable data, acting as a single source of truth for historical records.

  4. Schema Discovery (AWS Glue Crawler): Once raw data lands in S3, an AWS Glue Crawler is run (either on a schedule or triggered). The crawler scans the S3 path, infers the schema of the raw data (e.g., JSON structure, CSV columns), and registers this schema in the AWS Glue Data Catalog. This makes the raw data discoverable and queryable by other AWS services like Athena and Glue Jobs.
  5. ETL Processing (AWS Glue Job): An AWS Glue ETL Job (typically written in PySpark) is then triggered. This job reads the raw data from S3, leveraging the schema defined in the Glue Data Catalog. It performs comprehensive transformations:
    • Filtering: Removing irrelevant records.
    • Cleaning: Handling missing values, correcting data types.
    • Enrichment: Joining with other datasets (e.g., customer profiles, product catalogs) to add context.
    • Transformation: Reshaping data, aggregating metrics, converting data formats (e.g., from raw JSON to structured Parquet).

    After transformation, the Glue Job writes the processed, clean, and structured data into a new location in S3 (often in a columnar format like Parquet or ORC for optimized query performance). This S3 location becomes our “processed data zone” or “curated data lake layer.” Additionally, the Glue Job directly loads the final analytical tables into Amazon Redshift.

  6. Data Warehousing (Amazon Redshift): Amazon Redshift is the final destination for our analytical data. The processed data from the Glue Job is loaded into Redshift tables, optimized for fast querying and reporting. BI tools, dashboards, and data analysts connect directly to Redshift to run complex analytical queries on this data.

This architecture provides a modular, scalable, and resilient pipeline. Each component can be scaled independently, and the use of serverless services like Kinesis Firehose, Glue, and Lambda minimizes operational overhead.

Building Scalable Data Pipelines with AWS Kinesis, Glue, and Redshift
Generated Image

Deep Dive: Building the Pipeline Step-by-Step

Let’s walk through building this pipeline with a practical scenario: processing website clickstream data. Imagine a high-traffic e-commerce site generating thousands of click events per second. We want to capture these events, transform them, and analyze user behavior in Redshift.

Step 1: Ingesting Data with Amazon Kinesis Data Streams

First, we need a Kinesis Data Stream to capture our raw clickstream events. Each event might be a JSON object containing user ID, timestamp, page URL, event type (e.g., ‘page_view’, ‘add_to_cart’), and other relevant metadata.

Creating a Kinesis Data Stream (AWS CLI):

aws kinesis create-stream \
    --stream-name website-clickstream-raw \
    --shard-count 3

Here, we create a stream named `website-clickstream-raw` with 3 shards. The number of shards determines the throughput capacity (both read and write). For a production system, you’d calculate this based on your expected data volume and record size.

Producer Code Example (Python Boto3):

Our web servers or client-side applications would send events to this stream. Here’s a Python example simulating a producer:

import boto3
import json
import time
import random

kinesis_client = boto3.client('kinesis', region_name='us-east-1')
stream_name = 'website-clickstream-raw'

def generate_click_event():
    user_id = f"user_{random.randint(1, 1000)}"
    session_id = f"session_{random.randint(1, 500)}"
    event_type = random.choice(['page_view', 'add_to_cart', 'purchase', 'search'])
    page_url = f"/products/{random.randint(100, 999)}" if event_type != 'search' else "/search"
    timestamp = int(time.time() * 1000) # Milliseconds since epoch
    
    event = {
        "user_id": user_id,
        "session_id": session_id,
        "timestamp": timestamp,
        "event_type": event_type,
        "page_url": page_url,
        "product_id": random.randint(1, 50) if event_type in ['add_to_cart', 'purchase'] else None,
        "search_query": f"query_{random.randint(1, 20)}" if event_type == 'search' else None
    }
    return event

def put_record(event):
    partition_key = event['user_id'] # Use user_id for consistent routing to shards
    record = {
        'Data': json.dumps(event),
        'PartitionKey': partition_key
    }
    try:
        response = kinesis_client.put_record(
            StreamName=stream_name,
            Data=record['Data'],
            PartitionKey=record['PartitionKey']
        )
        # print(f"Successfully put record: {response['SequenceNumber']} for user {partition_key}")
    except Exception as e:
        print(f"Error putting record: {e}")

if __name__ == "__main__":
    print(f"Sending clickstream events to Kinesis stream: {stream_name}. Press Ctrl+C to stop.")
    try:
        while True:
            event = generate_click_event()
            put_record(event)
            time.sleep(0.1) # Send a record every 100ms
    except KeyboardInterrupt:
        print("Producer stopped.")

Key considerations:

  • Partition Key: Crucial for Kinesis. Records with the same partition key go to the same shard. Using `user_id` ensures that all events from a single user are processed in order within a shard, which is important for session tracking or user behavior analysis. However, it’s vital to choose a key that distributes data evenly across shards to prevent hot shards.
  • Shard Count: Determines throughput. Each shard provides 1 MB/second or 1000 records/second for writes, and 2 MB/second for reads. Adjust `shard-count` based on your expected peak ingestion rate.

Step 2: Landing Raw Data in S3 (via Kinesis Firehose)

For simplicity and serverless operation, we’ll use Kinesis Firehose to deliver our raw Kinesis Data Stream events to an S3 bucket. Firehose can also perform a basic JSON-to-Parquet conversion, which is excellent for analytical querying later.

Creating an S3 Bucket for Raw Data:

aws s3 mb s3://khadervali-clickstream-raw-data-lake-us-east-1

Creating a Kinesis Firehose Delivery Stream:

We’ll configure Firehose to read from our Kinesis Data Stream, optionally transform it, and write to S3.

  1. Go to the Kinesis console.
  2. Select “Delivery streams” and “Create delivery stream.”
  3. Source: Choose “Amazon Kinesis Data Streams” and select `website-clickstream-raw`.
  4. Process records: Enable “Record format conversion.” Select “Apache Parquet” as the output format. This is a powerful feature as Parquet is columnar, compressed, and highly efficient for analytical queries.
  5. Destination: Choose “Amazon S3.”
  6. S3 Destination: Specify your S3 bucket (e.g., `khadervali-clickstream-raw-data-lake-us-east-1`).
    • Prefix: `raw/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/` (This partitions data by year, month, day, which is crucial for efficient querying).
    • Error output prefix: `errors/`
  7. Buffer hints: Set buffer size (e.g., 64 MB) and buffer interval (e.g., 300 seconds). Firehose delivers data in batches when either condition is met.
  8. IAM Role: Create or choose an IAM role that grants Firehose permissions to read from Kinesis Data Stream and write to S3.

Once configured, Firehose will automatically start consuming records from your Kinesis Data Stream, batching them, converting them to Parquet (if configured), and delivering them to your S3 bucket. This lands our raw, immutable data in a cost-effective data lake storage.

Why S3 as a landing zone?

  • Durability and Availability: S3 provides 99.999999999% (11 nines) durability.
  • Scalability: Virtually unlimited storage capacity.
  • Cost-Effective: Very low storage costs, especially with lifecycle policies moving older data to Glacier.
  • Open Formats: Supports open formats like Parquet, which are optimal for analytics.
  • Foundation for Data Lake: S3 acts as the central repository for all raw and processed data, supporting various downstream analytics tools.
Building Scalable Data Pipelines with AWS Kinesis, Glue, and Redshift
Generated Image

Step 3: Discovering Schema with AWS Glue Crawlers

Now that our raw data (in Parquet format) is landing in S3, we need to make its schema discoverable. AWS Glue Crawlers automate this process.

Creating a Glue Crawler:

  1. Go to the AWS Glue console.
  2. Under “Data Catalog,” select “Crawlers” and “Create crawler.”
  3. Crawler name: `clickstream_raw_crawler`
  4. Data sources: Add a data source.
    • Data source: S3
    • Include path: `s3://khadervali-clickstream-raw-data-lake-us-east-1/raw/` (point it to the root of your raw data, the crawler will find partitions).
  5. IAM Role: Create or choose an IAM role that grants Glue permissions to read from S3 and write to the Glue Data Catalog.
  6. Schedule: For a pipeline processing continuous data, you might schedule it to run hourly or daily, depending on how frequently schema changes are expected or how fresh you need your metadata to be. For initial setup, “Run on demand” is fine.
  7. Output:
    • Database: Create a new database, e.g., `clickstream_db`.
    • Table prefix: `raw_` (Optional, but good for organization. So, your table might be `raw_website_clickstream_raw`).

After creating, run the crawler. It will scan the S3 path, infer the schema from the Parquet files, detect the `year`, `month`, `day` partitions, and create a table in the `clickstream_db` database within the Glue Data Catalog. This table now represents your raw clickstream data, ready for ETL with Glue Jobs or direct querying with Athena.

Importance of Glue Data Catalog:

  • Centralized Metadata: A single source of truth for schemas across your data lake.
  • Interoperability: Services like Athena, Glue, Redshift Spectrum, and EMR can all use the same Data Catalog definitions.
  • Schema Evolution: Crawlers can detect schema changes over time.

Step 4: Transforming and Loading Data with AWS Glue Jobs

Now that our raw data is cataloged, we can use an AWS Glue Job to transform it. For our clickstream data, transformations might include:

  • Parsing any remaining semi-structured fields.
  • Type casting to ensure correct data types (e.g., converting timestamp string to actual timestamp).
  • Filtering out irrelevant events.
  • Adding derived fields (e.g., extracting browser information from user agent strings).
  • Loading the transformed data into our Amazon Redshift data warehouse.

Creating a Glue Job:

  1. Go to the AWS Glue console.
  2. Under “ETL,” select “Jobs” and “Create job.”
  3. Job name: `clickstream_transform_to_redshift`
  4. IAM Role: Choose an IAM role with permissions for S3 (read/write), Glue Data Catalog (read), and Redshift (write via COPY command or Redshift connector). This role needs to be able to assume the Redshift IAM role for COPY operations.
  5. Type: “Spark” (for PySpark script).
  6. Glue version: Choose the latest Glue version (e.g., Spark 3.1, Python 3).
  7. Data processing units (DPUs): Start with 2 DPUs for development, scale up as needed.
  8. Connections: We need a connection to Redshift.
    • Under “Data Catalog -> Connections,” “Add connection.”
    • Connection type: “Amazon Redshift.”
    • JDBC URL: Get this from your Redshift cluster details.
    • Username/Password: Redshift master user credentials.
    • Ensure Redshift is accessible from Glue (e.g., within the same VPC or via VPC peering/endpoints).
    • Name this connection, e.g., `redshift-clickstream-connection`.

Glue PySpark Script Example:

This script will read from our raw clickstream data (via Glue Data Catalog), perform some basic transformations, and then write to a Redshift table.

import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark.sql.functions import col, from_unixtime, to_timestamp, lit

# @args
args = getResolvedOptions(sys.argv, ['JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# 1. Read Raw Data from Glue Data Catalog
# This uses the table created by the Glue Crawler from S3 Parquet files
raw_clickstream_dyf = glueContext.create_dynamic_frame.from_catalog(
database="clickstream_db",
table_name="raw_website_clickstream_raw",
transformation_ctx="raw_clickstream_dyf"
)

# Convert to Spark DataFrame for easier transformations
raw_clickstream_df = raw_clickstream_dyf.toDF()

# 2. Perform Transformations
# Example transformations:
# - Convert timestamp from milliseconds (long) to actual timestamp type
# - Ensure event_type is lowercase
# - Select relevant columns and cast them to appropriate types

processed_clickstream_df = raw_clickstream_df.select(
col("user_id").cast("string"),
col("session_id").cast("string"),
from_unixtime(col("timestamp") / 1000).cast("timestamp").alias("event_timestamp"), # Convert ms epoch to timestamp
col("event_type").cast("string").alias("event_type_raw"),
col("page_url").cast("string"),
col("product_id").cast("int"),
col("search_query").cast("string")
).withColumn("event_type", col("event_type_raw").cast("string").alias("event_type").lower()) # Example: lowercase event type

# Optional: Further cleaning, enrichment, filtering here
# For instance, drop rows where 'user_id' is null or invalid
processed_clickstream_df = processed_clickstream_df.filter(col("user_id").isNotNull())

# Select final columns to load to Redshift, dropping any intermediate ones
final_df_for_redshift = processed_clickstream_df.select(

Written by

Khader Vali

Senior Software Engineer specializing in cloud architecture, real-time systems, and enterprise-scale applications.

Share this article

Related Articles

Edge Computing Architecture Patterns & Use Cases Guide

Jun 16, 2026 · 17 min read

Mastering Infrastructure Testing: Terratest & Kitchen-Terraform

Jul 08, 2026 · 13 min read

GitOps with ArgoCD: Managing Kubernetes Deployments

Jun 18, 2026 · 16 min read