Development
CDK Deployed Data Lakehouse
A retrospect on third generation data lakehouse platforms deployed using AWS CDK
Introduction
We just completed the launch of a third generation Data Lakehouse. The platform hosts private data lakes and analytics dashboards to hundreds of clients around the world. Data is securely stored, segmented and delivered using AWS services such as Redshift, Glue, Lambda and S3.
This article focuses on the general architecture and how we were able to deliver individual big data solutions to customers in a deployable bundle with a fraction of the spend over other solutions.
Here's a quick breakdown of how this design compares to the standard and the self-hosted alternatives:
Comparison Overview: EMR + Glue vs. Lambda Lakehouse
| Category | AWS EMR + Glue (Managed) | Self-hosted EMR + Spark | Lambda Lakehouse |
|---|---|---|---|
| Infrastructure Cost | πΈ High β EMR clusters run 24/7 or per job | πΈ Moderate β Lower AWS cost, but team-managed | β Low β Event-driven, no persistent compute |
| Data Cataloging | β AWS Glue Crawlers ($0.44/DU/hr) | β Manual (or custom scripts) | β Automated in Lambda via metadata generation |
| Scalability | β High β managed scaling | β οΈ Manual tuning required | β Elastic β inherits Lambda auto-scaling |
| Startup Latency | β οΈ Minutes (EMR boot time) | β οΈ High (self-managed) | β Milliseconds (Lambda warm start mitigated) |
| Peak Performance | β High for massive joins or batch | β High if tuned | β οΈ Moderate β bounded by Lambda limits |
| Storage Format | β Supports Parquet/ORC | β Supports all formats | β Standardized to Parquet in S3 |
| Maintenance & Ops | β οΈ Requires Glue job tuning & partitioning | β High operational burden | β Minimal β infrastructure-as-code, Docker-based |
| Cost Efficiency | β οΈ Expensive for continuous processing | β οΈ Lower infra cost, but higher HR cost | β Extremely cost-efficient at scale |
| Typical Monthly Cost (Estimate) | $1,000β$20,000+ per project | $600β$10,000 (plus maintenance) | $50β$2,000 (depending on data volume & triggers) |
Cost Breakdown Examples
AWS Managed EMR + Glue
- EMR On-Demand Pricing (m5.xlarge, 4 vCPU, 16GB RAM):
$0.096 per core-hour Γ 4 cores β $0.384/hour
β For a modest 3-node cluster, running 8h/day:
3 Γ $0.384 Γ 8 Γ 30 β $276 per month - Glue Crawler Pricing:
$0.44 per DPU hourβ A typical crawler job costs$0.44β$5depending on dataset size.
β For 2 crawls per day:$2 Γ 30 = $60/month - Total Monthly (light usage): ~$400β$1000+
Heavy usage: upwards of $10K/month when factoring persistent compute or multiple jobs.
Self-hosted EMR + Spark
- Cost depends on instance types, cluster size, and data volume.
- Lower AWS bills, but offset by:
- Human time for ops (cluster tuning, monitoring, patching)
- Higher risk of downtime or poor job performance without Spark experts
Lambda-Based Lakehouse
- Lambda Cost:
$0.00001667 per GB-second + $0.20 per million invocations
β For 100GB processed per day in 512MB memory for 5 seconds:
100 GB Γ (5/2) Γ $0.00001667 β $0.42/day = $12.60/month - API Gateway/SQS Events/S3 Triggers: negligible if used efficiently.
- Glue Catalogs: This architecture auto-generates them β no crawler cost.
β
Est. Monthly Cost: $15β$300, even with growing data volumes.
Overview
Our platform is unique in a few ways:
- There is no monolithic lakehouse
- Every customer's self-contained datastore, metastore, transform layer, and presentation layer are deployed by a single registration pipeline event
- There are no Glue Crawlers, Spark, or EMR jobs for ETL/ELT
- The transform layer is object event driven
- The project integrates AWS CDK's CodePipeline strategy for CI/CD
Data Ingestion
Our ingress data policy is, generaly, "expect anything". Raw data files typically arrive in either:
- JSON
- CSV
- Avro
- Parquet
The Storage Layer
We use S3 for the data backend. Only S3.
Redshift Spectrum doesn't need to be loaded anywhere else but S3. Metadata gets stored alongside the transformation output which accounts for a large portion of what the Lakehouse serves.
The data written to S3 is:
- normalized
- partitioned
- cataloged
- mapped
- isolated
- reproducible
The Query Layer
As mentioned above, Redshift Spectrum allows Redshift to query external data stored in S3 through external schemas and external tables backed by catalogs such as Glue. This allows the analytics platform to reach into lake-backed data without requiring any dataset to be physically loaded into Redshift first.
This provides separation of concerns to the platform:
- S3 stores lake data.
- Glue stores table metadata.
- Redshift Spectrum queries S3 data as tables defined in glue.
- Redshift supports the analytic surface for external integration.
This is the key difference between a data lake and a data lakehouse. The data lake becomes an active part of the analytics system by fulfilling both the datastore and metastore on which analytics directly runs.
This and the Lambda transform layer entirely eliminates the need for batch rollups and manual data modeling. When data arrives in S3, the lambdas transfrom and store the data back to S3 and then create and update glue tables and partitions in one shot.
Ultimately, this results in data availability and readiness being achieved within seconds of a dataset being received.
The ETL Layer
The ETL layer is Lambda-driven.
Not every data transformation requires a persistent cluster. Not every ingestion path needs Spark. Not every pipeline is made better by adding a distributed compute engine and a four-hour onboarding document explaining why local testing is βnon-trivial.β
For this platform, the ingestion workflows were designed as lean processing units:
- Receive raw input.
- Detect format.
- Parse records.
- Infer candidate field types.
- Normalize into a standard schema representation.
- Write optimized Parquet output.
- Emit schema metadata.
- Trigger catalog registration.
- Make the data queryable.
This is not a universal claim that Lambda replaces Spark. It does not. Please do not build your next petabyte-scale feature engineering platform entirely out of Lambda functions.
But for a large class of customer-ingestion and normalization workloads, Lambda gives you elastic execution, operational simplicity and clean deployment boundaries. It also allows each deployment to scale independently.
The Cataloger
The cataloger is integral to what makes the this design possible.
It runs as a second lambda and watch event on the schema path generated by the ingest process. The catalog lambda generates:
- Glue database and table definitions
- storage descriptors
- partition keys
- partition locations
- Redshift external mappings
The ingestion process standardizes the data and the cataloger populates the metastore.
Multi-Tenant by Deployment
The platform is engineered to serve customers with their own pipeline and stack with dedicated resources and clearly segmented data backends. This gives us:
- cleaner security boundaries
- easier customer-specific scaling
- simpler blast-radius control
- independent deployment behavior
- clearer cost attribution
- reduced cross-customer coupling
- scalable repeatability
Deployment Automation
Everything is deployed through CDK and CodePipeline automation.
The infrastructure pipeline defines and deploys the lakehouse stack as code:
- storage resources
- Lambda ETL functions
- cataloging functions
- Glue metadata resources
- Redshift integration
- IAM boundaries
- customer-specific configuration
- deployment stages
The goal is automated, repeatable and scalable customer delivery.
Notable Issues
-
Some data producers chose v1 over v2 file formats in Parquet. This resulted in unexpected behavior, particularly in compatibility issues and performance drops.
-
The
INT96data type is one example of a deprecation from v1 and because we're not storing data in hadoop or using Scala we had to manually implement many of the ingestion routines that would normally convert these types automatically. -
Matching the data types when generating Glue tables required mapping and generating a compatible json table schema that reflrected the types accurately.
Likes: 1