Scaling Strategy - mukular/food-delivery-feastfast--architecture GitHub Wiki

Scaling Strategy

This document explains how the system is designed to scale from a few users to millions, covering backend architecture, database scaling, caching, real-time systems, and operational trade-offs.

The goal is predictable performance, horizontal scalability, and cost-efficient growth.


1. Scaling Philosophy

This platform follows these core principles:

  • Stateless application servers
  • Horizontal scaling over vertical scaling
  • Read-heavy optimization
  • Eventually consistent non-critical flows
  • Strict consistency for payments & orders

2. High-Level Architecture

Client (Web / Mobile)
        ↓
CDN (Static Assets)
        ↓
Load Balancer
        ↓
Node.js API (Express)
        ↓
--------------------------------
| MongoDB | Redis | Socket.IO |
--------------------------------

Each layer can scale independently.


3. Application Layer Scaling (Express)

Stateless Backend

  • No session data stored in memory
  • Sessions stored in Redis
  • JWT used only for identity, not authorization state

JWTs are used only for identity propagation, while authorization and session validity are enforced server-side using Redis-backed sessions.

This allows:

  • Unlimited horizontal scaling
  • Safe rolling deployments
  • Zero sticky-session dependency

Scaling Strategy

PM2 / Docker / Kubernetes
        ↓
Multiple API instances
        ↓
Shared Redis + MongoDB

4. Database Scaling (MongoDB)

Current Model

  • MongoDB Atlas (Replica Set)
  • Strong consistency for writes
  • Indexed reads

Scaling Reads

Read-heavy endpoints optimized using:

  • Proper indexing
  • Lean queries
  • Aggregation pipelines
  • Redis caching

Scaling Writes

Orders and payments are write-heavy.

Writes are:

  • Transactional
  • Short-lived
  • Idempotent where required

5. Database Indexing Strategy

Critical indexes include:

Order: { user, createdAt }
Order: { "shopOrders.shop", "shopOrders.status" }

Shop: { location: "2dsphere" }
Shop: { isActive, isApproved }

Item: { shop, category, price }
Coupon: { code, shop, isActive }

Indexes reduce query latency from O(n) to O(log n).


6. Redis Caching Strategy

Redis is used for:

  • Restaurant listing results
  • Menu pages
  • Session storage

Cache Key Design

restaurants:{rounded_lat}:{rounded_lng}:{filters}
menu:{shopId}:{filters}

Why Lat/Lng Rounding?

  • Prevents cache explosion
  • Reduces millions of keys → thousands
  • Used by Swiggy / Zomato

Example:

28.6139 → 28.61
77.2090 → 77.21

7. Cache TTL Strategy

Data TTL
Restaurant list 60 sec
Menu items 120 sec
Shop details 300 sec
Sessions 7 days

Short TTL ensures:

  • Freshness
  • Automatic eviction
  • Low memory pressure

8. Real-Time Scaling (Socket.IO)

Current Usage

  • Order status updates
  • Delivery location tracking
  • Live notifications

Scaling Strategy

Socket Server
     ↓
Redis Adapter
     ↓
Multiple Socket Nodes

This enables:

  • Cross-instance event delivery
  • Horizontal socket scaling
  • Fault tolerance

9. Delivery Tracking Optimization

To prevent overload:

  • Location updates throttled (e.g. every 5–10 seconds)
  • Distance-based updates only
  • Room-based emission (orderId)

This avoids:

  • Battery drain
  • Network congestion
  • Socket floods

10. Coupon System Scalability

Coupon logic avoids:

  • ❌ Reservation systems
  • ❌ Locks
  • ❌ Long-held resources

Instead:

  • Coupons consumed atomically during order creation
  • MongoDB transactions ensure correctness

This scales linearly without Redis locks.


11. Pagination & Data Windowing

Instead of infinite data:

  • Restaurants → paginated
  • Menu items → paginated
  • Orders → limited windows

This:

  • Reduces payload size
  • Improves cache hit ratio
  • Prevents memory spikes

12. Handling Traffic Spikes

Examples:

  • Lunch / dinner peak
  • Festival sales

Mitigation strategies:

  • Redis absorbs read pressure
  • CDN serves static assets
  • Horizontal autoscaling
  • Graceful degradation (cache-first)

13. Payment System Scaling

Payments are:

  • Event-driven
  • Webhook-based
  • Idempotent

Key design choices:

  • Webhooks verified cryptographically
  • No synchronous blocking
  • Fail-safe refund handling

14. Background Jobs (Future)

Can be added later using:

  • BullMQ
  • RabbitMQ

Use cases:

  • Order auto-cancellation
  • Coupon cleanup
  • Analytics aggregation

15. Cost-Aware Scaling

Design avoids:

  • Excessive Redis memory usage
  • Expensive DB joins
  • Unbounded socket connections

This keeps:

  • Hosting costs low
  • Predictable billing
  • Easy optimization

16. Failure Handling

Failure Handling
Redis down DB fallback
Socket failure Polling fallback
Webhook delay Idempotent retry
Partial deploy Stateless recovery

17. Why This Scaling Strategy Works

  • Proven industry patterns
  • Simple mental model
  • No over-engineering
  • Easy to debug
  • Cheap to operate