Real-World Project
E-Commerce Platform
Build a scalable shopping platform at Amazon scale with Cassandra!
๐ Project Overview
Build a real-world e-commerce platform!
The Challenge: ShopFast - Next-Gen E-Commerce
ShopFast is building the next Amazon. They need a database that can handle:
- ๐๏ธ Product catalog: 100 million products
- ๐ฅ User activity: 50 million active users
- ๐ Shopping carts: Real-time cart updates
- ๐ฆ Order history: 1 billion orders/year
- โญ Reviews & ratings: Millions of reviews
- ๐ Search & browse: Sub-second product search
Scale Requirements
| Products: | 100 million SKUs across 10,000 categories |
| Users: | 50 million monthly active users |
| Orders/Day: | 2.7 million (1B/year รท 365) |
| Peak Traffic: | Black Friday: 10x normal (27M orders/day) |
| Cart Updates: | ~100K writes/second during peak |
| Product Views: | 500K reads/second |
Why Cassandra?
- โ Linear scalability: Add nodes for Black Friday
- โ High availability: Zero downtime during sales
- โ Write throughput: 100K+ cart updates/second
- โ Geo-distribution: Global data centers
- โ Fast reads: Sub-10ms product lookups
๐ฏ Requirements & Use Cases
What we need to build!
Product Catalog
- Get product by ID (fast lookup)
- Browse products by category
- Search products by keywords
- View product details & images
- Check inventory availability
Shopping Cart
- Add/remove items from cart
- Update item quantities
- View cart contents
- Calculate cart total
- Save cart across sessions
Orders & History
- Place order (checkout)
- View order history
- Track order status
- Get order details
- Reorder past items
Reviews & Ratings
- Write product review
- View all product reviews
- Get average rating
- Sort reviews (helpful, recent)
- Review moderation
๐บ๏ธ Data Model Design
E-commerce data modeling!
E-Commerce Data Modeling Principles
- Denormalize for reads: Duplicate product data across tables
- User-centric partitions: user_id as partition key for personalized data
- Product-centric views: Separate tables for browsing catalog
- Time-bucketing: Orders partitioned by user + month
- Materialized views: Different access patterns = different tables
Query Patterns โ Table Design
| Query Pattern | Access Pattern | Table Design |
|---|---|---|
| Q1: Get product details | By product_id | products_by_id |
| Q2: Browse by category | By category + price/popularity | products_by_category |
| Q3: View shopping cart | By user_id | shopping_carts |
| Q4: Order history | By user_id + date | orders_by_user |
| Q5: Product reviews | By product_id + date | reviews_by_product |
| Q6: Get order details | By order_id | orders_by_id |
E-Commerce Data Flow
User Browses
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Product Catalog โ
โ - Browse categories โ
โ - Search products โ
โ - View details โ
โโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Shopping Cart โ
โ - Add to cart โ
โ - Update quantities โ
โ - Calculate total โ
โโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Checkout Process โ
โ - Create order โ
โ - Payment โ
โ - Inventory update โ
โโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Order History โ
โ - Track orders โ
โ - View past orders โ
โ - Reorder โ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Schema Design
Complete table schemas!
1
Keyspace Creation
-- Create keyspace
CREATE KEYSPACE shopfast
WITH replication = {
'class': 'NetworkTopologyStrategy',
'us-east': 3,
'us-west': 3,
'eu-west': 3
};
USE shopfast;
2
Products Table (Primary Lookup)
-- Product details by ID (fast lookup)
CREATE TABLE products_by_id (
product_id UUID PRIMARY KEY,
name TEXT,
description TEXT,
brand TEXT,
category TEXT,
price DECIMAL,
discount_percent DECIMAL,
image_urls LIST<TEXT>,
attributes MAP<TEXT, TEXT>, -- size, color, etc
inventory_count INT,
rating_avg DECIMAL,
rating_count INT,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
-- Query: Get product details
SELECT * FROM products_by_id WHERE product_id = ?;
3
Products by Category (Browse)
-- Products organized by category for browsing
CREATE TABLE products_by_category (
category TEXT, -- Partition key
price DECIMAL, -- Clustering key (sort)
product_id UUID, -- Clustering key
name TEXT,
brand TEXT,
image_url TEXT,
rating_avg DECIMAL,
discount_percent DECIMAL,
PRIMARY KEY (category, price, product_id)
) WITH CLUSTERING ORDER BY (price ASC, product_id ASC);
-- Query: Browse category by price
SELECT * FROM products_by_category
WHERE category = 'Electronics'
LIMIT 50;
-- Query: Filter by price range
SELECT * FROM products_by_category
WHERE category = 'Electronics'
AND price >= 100 AND price <= 500;
4
Shopping Cart Table
-- User's shopping cart (fast read/write)
CREATE TABLE shopping_carts (
user_id UUID, -- Partition key
product_id UUID, -- Clustering key
product_name TEXT,
price DECIMAL,
quantity INT,
image_url TEXT,
added_at TIMESTAMP,
PRIMARY KEY (user_id, product_id)
);
-- Query: Get user's cart
SELECT * FROM shopping_carts WHERE user_id = ?;
-- Query: Add to cart
INSERT INTO shopping_carts (user_id, product_id, product_name, price, quantity, added_at)
VALUES (?, ?, ?, ?, ?, toTimestamp(now()));
-- Query: Update quantity
UPDATE shopping_carts
SET quantity = ?
WHERE user_id = ? AND product_id = ?;
-- Query: Remove from cart
DELETE FROM shopping_carts
WHERE user_id = ? AND product_id = ?;
5
Orders Table (by User)
-- Orders partitioned by user + month (time-bucketing)
CREATE TABLE orders_by_user (
user_id UUID,
order_month TEXT, -- '2024-01' (bucket)
order_time TIMESTAMP,
order_id UUID,
total_amount DECIMAL,
status TEXT, -- pending, shipped, delivered
shipping_address TEXT,
items LIST<FROZEN<order_item>>,
PRIMARY KEY ((user_id, order_month), order_time, order_id)
) WITH CLUSTERING ORDER BY (order_time DESC, order_id ASC);
-- UDT for order items
CREATE TYPE order_item (
product_id UUID,
product_name TEXT,
price DECIMAL,
quantity INT
);
-- Query: Get recent orders
SELECT * FROM orders_by_user
WHERE user_id = ? AND order_month = '2024-01';
6
Orders by ID (Direct Lookup)
-- Order details by order ID (for tracking)
CREATE TABLE orders_by_id (
order_id UUID PRIMARY KEY,
user_id UUID,
order_time TIMESTAMP,
total_amount DECIMAL,
status TEXT,
shipping_address TEXT,
tracking_number TEXT,
items LIST<FROZEN<order_item>>
);
-- Query: Track order
SELECT * FROM orders_by_id WHERE order_id = ?;
7
Product Reviews Table
-- Reviews partitioned by product
CREATE TABLE reviews_by_product (
product_id UUID,
review_time TIMESTAMP,
review_id UUID,
user_id UUID,
user_name TEXT,
rating INT, -- 1-5 stars
title TEXT,
review_text TEXT,
verified_purchase BOOLEAN,
helpful_count COUNTER,
PRIMARY KEY (product_id, review_time, review_id)
) WITH CLUSTERING ORDER BY (review_time DESC, review_id ASC);
-- Query: Get product reviews
SELECT * FROM reviews_by_product
WHERE product_id = ?
LIMIT 10;
8
User Profiles Table
-- User account information
CREATE TABLE users (
user_id UUID PRIMARY KEY,
email TEXT,
full_name TEXT,
phone TEXT,
addresses LIST<FROZEN<address>>,
created_at TIMESTAMP,
last_login TIMESTAMP
);
CREATE TYPE address (
address_id UUID,
street TEXT,
city TEXT,
state TEXT,
zip TEXT,
country TEXT,
is_default BOOLEAN
);
๐ป Implementation
Python implementation!
Product Service
# product_service.py
from cassandra.cluster import Cluster
from decimal import Decimal
import uuid
class ProductService:
def __init__(self, contact_points):
cluster = Cluster(contact_points)
self.session = cluster.connect('shopfast')
# Prepared statements
self.get_product = self.session.prepare("""
SELECT * FROM products_by_id WHERE product_id = ?
""")
self.browse_category = self.session.prepare("""
SELECT * FROM products_by_category
WHERE category = ?
LIMIT ?
""")
def get_product_details(self, product_id):
"""Get complete product information"""
row = self.session.execute(self.get_product, (product_id,)).one()
if row:
return {
'product_id': row.product_id,
'name': row.name,
'description': row.description,
'brand': row.brand,
'category': row.category,
'price': float(row.price),
'discount_percent': float(row.discount_percent) if row.discount_percent else 0,
'image_urls': row.image_urls,
'attributes': row.attributes,
'inventory_count': row.inventory_count,
'rating_avg': float(row.rating_avg) if row.rating_avg else 0,
'rating_count': row.rating_count
}
return None
def browse_category(self, category, limit=50, min_price=None, max_price=None):
"""Browse products by category with price filter"""
if min_price and max_price:
query = """
SELECT * FROM products_by_category
WHERE category = ?
AND price >= ?
AND price <= ?
LIMIT ?
"""
rows = self.session.execute(
query,
(category, Decimal(str(min_price)), Decimal(str(max_price)), limit)
)
else:
rows = self.session.execute(self.browse_category, (category, limit))
return [
{
'product_id': row.product_id,
'name': row.name,
'brand': row.brand,
'price': float(row.price),
'image_url': row.image_url,
'rating_avg': float(row.rating_avg) if row.rating_avg else 0,
'discount_percent': float(row.discount_percent) if row.discount_percent else 0
}
for row in rows
]
def check_inventory(self, product_id):
"""Check if product is in stock"""
row = self.session.execute(self.get_product, (product_id,)).one()
return row.inventory_count > 0 if row else False
# Usage
product_service = ProductService(['localhost'])
# Get product
product = product_service.get_product_details(product_id)
print(f"{product['name']}: ${product['price']}")
# Browse electronics under $500
products = product_service.browse_category(
'Electronics',
min_price=100,
max_price=500,
limit=20
)
Shopping Cart Service
# cart_service.py
from datetime import datetime
class CartService:
def __init__(self, session):
self.session = session
self.add_item = session.prepare("""
INSERT INTO shopping_carts
(user_id, product_id, product_name, price, quantity, image_url, added_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
""")
self.update_quantity = session.prepare("""
UPDATE shopping_carts
SET quantity = ?
WHERE user_id = ? AND product_id = ?
""")
self.remove_item = session.prepare("""
DELETE FROM shopping_carts
WHERE user_id = ? AND product_id = ?
""")
def add_to_cart(self, user_id, product_id, product_name, price, quantity, image_url):
"""Add item to cart"""
self.session.execute(
self.add_item,
(user_id, product_id, product_name, Decimal(str(price)),
quantity, image_url, datetime.now())
)
def update_item_quantity(self, user_id, product_id, quantity):
"""Update quantity of item in cart"""
if quantity <= 0:
self.remove_from_cart(user_id, product_id)
else:
self.session.execute(self.update_quantity, (quantity, user_id, product_id))
def remove_from_cart(self, user_id, product_id):
"""Remove item from cart"""
self.session.execute(self.remove_item, (user_id, product_id))
def get_cart(self, user_id):
"""Get all items in user's cart"""
query = "SELECT * FROM shopping_carts WHERE user_id = ?"
rows = self.session.execute(query, (user_id,))
items = []
total = 0
for row in rows:
item_total = float(row.price) * row.quantity
total += item_total
items.append({
'product_id': row.product_id,
'product_name': row.product_name,
'price': float(row.price),
'quantity': row.quantity,
'image_url': row.image_url,
'item_total': item_total
})
return {
'items': items,
'total_amount': total,
'item_count': len(items)
}
def clear_cart(self, user_id):
"""Clear entire cart (after checkout)"""
query = "DELETE FROM shopping_carts WHERE user_id = ?"
self.session.execute(query, (user_id,))
# Usage
cart_service = CartService(session)
# Add to cart
cart_service.add_to_cart(
user_id=user_id,
product_id=product_id,
product_name="Wireless Headphones",
price=99.99,
quantity=1,
image_url="https://..."
)
# Get cart
cart = cart_service.get_cart(user_id)
print(f"Cart total: ${cart['total_amount']:.2f}")
๐ Cart & Orders Flow
Checkout process!
Order Service
# order_service.py
from datetime import datetime
import uuid
class OrderService:
def __init__(self, session):
self.session = session
def create_order(self, user_id, cart_items, shipping_address):
"""Create order from cart"""
order_id = uuid.uuid4()
order_time = datetime.now()
order_month = order_time.strftime('%Y-%m')
# Calculate total
total_amount = sum(item['price'] * item['quantity'] for item in cart_items)
# Convert cart items to order items
order_items = [
{
'product_id': item['product_id'],
'product_name': item['product_name'],
'price': Decimal(str(item['price'])),
'quantity': item['quantity']
}
for item in cart_items
]
# Insert into orders_by_user
self.session.execute("""
INSERT INTO orders_by_user
(user_id, order_month, order_time, order_id, total_amount, status, shipping_address, items)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (user_id, order_month, order_time, order_id,
Decimal(str(total_amount)), 'pending', shipping_address, order_items))
# Insert into orders_by_id (for tracking)
self.session.execute("""
INSERT INTO orders_by_id
(order_id, user_id, order_time, total_amount, status, shipping_address, items)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", (order_id, user_id, order_time, Decimal(str(total_amount)),
'pending', shipping_address, order_items))
return {
'order_id': order_id,
'order_time': order_time,
'total_amount': total_amount
}
def get_order_history(self, user_id, month=None):
"""Get user's order history"""
if not month:
month = datetime.now().strftime('%Y-%m')
query = """
SELECT * FROM orders_by_user
WHERE user_id = ? AND order_month = ?
"""
rows = self.session.execute(query, (user_id, month))
return [
{
'order_id': row.order_id,
'order_time': row.order_time,
'total_amount': float(row.total_amount),
'status': row.status,
'item_count': len(row.items)
}
for row in rows
]
def track_order(self, order_id):
"""Track order status"""
query = "SELECT * FROM orders_by_id WHERE order_id = ?"
row = self.session.execute(query, (order_id,)).one()
if row:
return {
'order_id': row.order_id,
'status': row.status,
'tracking_number': row.tracking_number,
'order_time': row.order_time,
'total_amount': float(row.total_amount)
}
return None
# Complete checkout flow
def checkout(user_id, shipping_address):
# 1. Get cart
cart = cart_service.get_cart(user_id)
if not cart['items']:
return {'error': 'Cart is empty'}
# 2. Create order
order = order_service.create_order(
user_id,
cart['items'],
shipping_address
)
# 3. Clear cart
cart_service.clear_cart(user_id)
# 4. Update inventory (separate service)
# inventory_service.decrease_stock(cart['items'])
return order
โก Performance Optimization
Production optimization!
Caching Strategy
- Redis cache: Product details (5-min TTL)
- CDN: Product images & static data
- Application cache: Category listings
- Cache invalidation: On price/inventory updates
- Result: 90%+ cache hit rate
Search Optimization
- Elasticsearch: Product search
- Sync pipeline: Cassandra โ ES
- Faceted search: Brand, price, ratings
- Autocomplete: Suggest as you type
- Response time: <100ms for searches
Query Optimization
- Denormalization: Duplicate data across tables
- Prepared statements: All queries
- Batch operations: Checkout process
- Async writes: Non-critical updates
- Read consistency: ONE for speed
Scalability
- Time-bucketing: Orders by month
- Partition size: <100MB per partition
- Black Friday prep: Add nodes in advance
- Auto-scaling: Based on metrics
- Linear growth: 2x nodes = 2x capacity
Anti-Patterns to Avoid
- โ Don't: Use ALLOW FILTERING in production
- โ Don't: Store large images in Cassandra (use S3/CDN)
- โ Don't: Create unbounded partitions (use time-bucketing)
- โ Don't: Use SELECT * on large tables
- โ Don't: Perform JOINs client-side at scale
- โ Do: Denormalize data for read efficiency
- โ Do: Use separate tables per query pattern
๐ Deployment Architecture
Production deployment!
Multi-Region E-Commerce Architecture
Global Load Balancer
โ
โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
US-East US-West EU-West
Region Region Region
โ โ โ
โโโโโโดโโโโโ โโโโโโดโโโโโ โโโโโโดโโโโโ
โ โ โ โ โ โ
โผ โผ โผ โผ โผ โผ
Redis Cassandra Redis Cassandra Redis Cassandra
Cache (6 nodes) Cache (6 nodes) Cache (6 nodes)
โ โ โ โ โ โ
โโโโโโโโโโโผโโโโโโโโโดโโโโโโโโผโโโโโโโโโดโโโโโโโโโ
โ โ
โผ โผ
Elasticsearch S3 (Images)
(Product Search) (CDN CloudFront)
Production Checklist
| Component | Configuration | Status |
|---|---|---|
| Cluster Size | 18 nodes (6 per region) | โ |
| Replication | RF=3 per region (9 total) | โ |
| Write Throughput | 100K writes/second (peak) | โ |
| Read Latency | p99 < 10ms | โ |
| Caching | Redis + CDN (90% hit rate) | โ |
| Search | Elasticsearch cluster | โ |
| Monitoring | Datadog + PagerDuty | โ |
| Disaster Recovery | Cross-region replication | โ |
๐ Project Complete!
You built a production-ready e-commerce platform at Amazon scale!
๐ What You Built:
- ๐๏ธ Scale: 100M products, 50M users, 27M orders/day (peak)
- ๐บ๏ธ Data model: 8 tables covering all use cases
- ๐ Schema: Products, cart, orders, reviews, users
- ๐ป Implementation: Product, cart, order services
- ๐ Shopping flow: Browse โ Cart โ Checkout โ Orders
- โก Optimization: Redis cache, ES search, denormalization
- ๐ Deployment: Multi-region with 18 nodes
๐ก Key Learnings:
- Denormalization: Duplicate data for read efficiency
- Query-driven design: One table per access pattern
- Shopping cart: Simple partition by user_id
- Time-bucketing: Orders by user + month
- Separate lookup tables: orders_by_id for tracking
- Caching strategy: Redis + CDN for 90% hit rate
- Search integration: Elasticsearch for product search
๐ Architecture Highlights:
- โ 8 tables: products_by_id, by_category, cart, orders, reviews
- โ Denormalized: Product data duplicated for performance
- โ Write path: 100K cart updates/second
- โ Read path: Sub-10ms with caching
- โ Global: 3 regions, 18 nodes, RF=9
- โ Zero downtime: Even during Black Friday
๐ Next Steps:
- ๐ Add analytics (product views, conversion rates)
- ๐ค Implement recommendation engine (ML)
- ๐ณ Add payment gateway integration
- ๐ง Build email notification system
- ๐ฑ Create mobile app (iOS/Android)
- ๐ Expand to more regions
Congratulations on completing this advanced Cassandra e-commerce project! ๐
font-weight: 700;"> ๐ฏ You're ready to build e-commerce at scale! ๐Ship it to production!
Advertisement
Responsive Ad