Legacy Monolith Migration: Lift & Shift to Multi-AZ Auto Scaling EC2
Re-platforming a stateful Django/Rails monolith to horizontal Auto Scaling EC2 behind an ALB with externalized Redis session storage.
1. Business Problem & Context
An established e-learning company hosted their monolithic Django application on a single large on-premise virtual machine. Whenever traffic surged during exams or flash sales, the server froze. Furthermore, user sessions were stored in local server memory, meaning rebooting or patching the server forcibly logged out all active students.
2. Requirements & Constraints
- Zero Downtime During Deployments: Eliminate maintenance maintenance windows.
- Multi-AZ Fault Tolerance: Survive an entire AWS Availability Zone failure.
- Stateless Compute: Externalize user sessions and file uploads.
- Minimal Code Refactoring: Must run existing Django codebase without rewriting into microservices.
3. Architecture Overview & Data Flow
Interactive Architecture Diagram (Use controls to zoom & pan)
- Session Externalization: Configured Django session backend to store sessions in Amazon ElastiCache Redis cluster.
- Asset Offloading: User-uploaded media files were redirected from local disk storage to an Amazon S3 bucket.
- Golden AMI & Launch Template: Automated image baking with Packer/EC2 Image Builder, enabling new instances to boot and pass ALB health checks in under 3 minutes.
- Auto Scaling Target Tracking: ASG automatically adds instances when average CPU utilization exceeds 65%.
4. AWS Services Used & Rationales
AWS Services Architecture Rationale
Concrete reasons why these specific services were chosen over alternatives
| Service | Category | Architectural Rationale ("Why this service?") |
|---|---|---|
| Auto Scaling Groups | Compute | Maintains desired instance count across multiple AZs and replaces unhealthy instances automatically. |
| Application Load Balancer | Networking | Terminates SSL/TLS and performs HTTP health check polling on /healthz. |
| Amazon ElastiCache Redis | Database | Sub-millisecond distributed session store shared across all EC2 instances. |
5. Key Design Trade-offs
Architecture Decision & Trade-Off Matrix
Evaluating alternative approaches under real-world constraints
Single Oversized EC2 Instance
- + Zero refactoring of local sessions
- − Single point of failure
- − Downtime during updates
- − Wasted idle compute costs
Horizontal ASG + ElastiCache (Chosen)
✓ Chosen Design- + High availability across AZs
- + Scales dynamically with exam traffic
- + Zero-downtime rolling updates
- − Requires external session management configuration
6. Implementation Highlights
Automation EC2 Launch Template User Data Script
#!/bin/bash
# Fetch latest app bundle from S3
aws s3 cp s3://app-deployments/django-latest.tar.gz /app/bundle.tar.gz
cd /app && tar -xzf bundle.tar.gz
# Inject DB & Redis credentials from SSM Parameter Store
export DATABASE_URL=$(aws ssm get-parameter --name "/prod/db_url" --with-decryption --query "Parameter.Value" --output text)
export REDIS_URL=$(aws ssm get-parameter --name "/prod/redis_url" --query "Parameter.Value" --output text)
# Start Gunicorn server
gunicorn app.wsgi:application --bind 0.0.0.0:8000 --workers 4 7. Results & Key Metrics
- Uptime: Increased from 98.2% to 99.97%.
- Rollout Downtime: Reduced from 45 minutes per release to 0 minutes using ASG instance refresh.
8. Key Architectural Takeaways
Monolith Rule: You do not need to rewrite your application into microservices to achieve high availability. Externalizing session state and local file storage allows any legacy monolith to scale horizontally across multiple AZs.