
I built this pipeline to get hands-on experience with the tools that power data infrastructure at companies like Netflix and Uber. It’s a complete implementation showing how different technologies work together to create a resilient streaming data system.
What I Built
A fully functional data pipeline that:
- Ingests data through Airflow-orchestrated jobs
- Streams it through Kafka for reliable delivery
- Processes with Spark for transformations
- Stores in Cassandra for high-speed access
The interesting part wasn’t just getting these tools to work individually - it was making them work together seamlessly. Each component has its quirks and getting them to play nice required understanding their internals.
Technical Implementation
The Stack
Apache Airflow: Orchestrates the whole pipeline. I wrote DAGs that:
- Fetch data from APIs (using randomuser.me for demo data)
- Handle retries and failures gracefully
- Monitor pipeline health
Kafka + Zookeeper: The nervous system of the pipeline
- Configured multi-broker setup for fault tolerance
- Tuned partition strategy for parallel processing
- Implemented proper serialization for data integrity
Spark Streaming: Where the magic happens
- Built streaming jobs that process data in micro-batches
- Implemented transformations and aggregations
- Set up checkpointing for failure recovery
Cassandra: The final destination
- Designed tables optimized for write throughput
- Denormalized data model for fast reads
- Configured replication for high availability
Docker Everything
The entire stack runs in Docker containers. This was crucial because:
- Anyone can spin up the whole pipeline with one command
- No “works on my machine” problems
- Easy to experiment without breaking things
Getting the networking right was tricky - Kafka needs to advertise correct addresses, Spark workers need to find the master, and everything needs to reach Cassandra.
Challenges and Solutions
Kafka’s Zookeeper dependency: Understanding why Kafka needs Zookeeper taught me about distributed consensus. When Zookeeper went down during testing, Kafka became headless - a good lesson in failure modes.
Spark memory management: Initial runs kept failing with OOM errors. Learned to tune executor memory, understand the difference between driver and executor, and how to partition data properly.
Cassandra consistency levels: Choosing between consistency and availability isn’t theoretical when your writes start failing. Settled on LOCAL_QUORUM for the right balance.
Performance Insights
The pipeline can handle significant load on modest hardware:
- Processes thousands of events per second
- Scales horizontally by adding Kafka partitions and Spark workers
- Cassandra handles writes without breaking a sweat
But more importantly, I learned where the bottlenecks appear:
- Network I/O between Docker containers
- Serialization/deserialization overhead
- Checkpoint storage for Spark streaming
Real Learning
This project taught me that distributed systems are hard not because of any single component, but because of the interactions between them. Some key lessons:
- Start simple: My first version just moved data from A to B. Added complexity gradually.
- Monitor everything: Added Prometheus + Grafana to understand what’s actually happening
- Failure is normal: Every component will fail. Design for it.
- Documentation matters: Future me thanked past me for writing down configuration decisions
Practical Applications
While this uses synthetic data, the architecture applies to:
- E-commerce event streams
- IoT sensor networks
- Financial transaction processing
- Log aggregation systems
The patterns are the same whether you’re processing user clicks or temperature readings.
Full implementation with setup instructions and monitoring dashboards: GitHub