Scaling R Commerce¶
Scale R Commerce horizontally and vertically to handle increased traffic and load.
Scaling Strategies¶
Vertical Scaling (Scale Up)¶
Increase resources on a single server:
| Resource | Impact | Limit |
|---|---|---|
| CPU | More concurrent requests | Single machine limit |
| RAM | Larger cache, more connections | Cost increases |
| Disk I/O | Faster database queries | SSD/NVMe required |
| Network | Higher throughput | NIC bandwidth |
Horizontal Scaling (Scale Out)¶
Add more servers behind a load balancer:
┌─────────────────┐
│ Load Balancer │
│ (nginx) │
└────────┬────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ R Commerce │ │ R Commerce │ │ R Commerce │
│ Instance 1│ │ Instance 2│ │ Instance 3│
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────┼────────────────┘
│
┌────────▼────────┐
│ PostgreSQL │
│ (Primary) │
└─────────────────┘
│
┌────────▼────────┐
│ Redis │
│ (Shared) │
└─────────────────┘
Stateless Architecture¶
R Commerce is designed to be stateless:
- No local sessions: Use Redis for session storage
- Shared storage: Use S3/MinIO for uploads
- Centralized config: All instances share same config
[cache]
cache_type = "Redis"
redis_url = "redis://redis-cluster:6379"
[media]
storage_type = "S3"
s3_bucket = "rcommerce-uploads"
s3_region = "us-east-1"
Database Scaling¶
Read Replicas¶
Distribute read queries across replicas:
[database]
# Write to primary
host = "postgres-primary.internal"
port = 5432
# Read from replicas (application-level)
read_replicas = [
"postgres-replica-1.internal:5432",
"postgres-replica-2.internal:5432"
]
Connection Pooling¶
Use PgBouncer for connection pooling:
; pgbouncer.ini
[databases]
rcommerce = host=postgres-primary port=5432 dbname=rcommerce
[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = md5
pool_mode = transaction
max_client_conn = 10000
default_pool_size = 25
Database Sharding¶
For very large datasets, shard by tenant:
// Shard key based on tenant_id
fn get_shard(tenant_id: Uuid) -> &'static str {
match tenant_id.as_u128() % 4 {
0 => "postgres-shard-0",
1 => "postgres-shard-1",
2 => "postgres-shard-2",
_ => "postgres-shard-3",
}
}
Caching Strategy¶
Multi-Level Cache¶
┌─────────────────────────────────────┐
│ Client Browser │
│ (HTTP Cache, Local) │
└───────────────┬─────────────────────┘
│
┌───────────────▼─────────────────────┐
│ CDN (CloudFlare) │
│ (Edge Cache, 5min TTL) │
└───────────────┬─────────────────────┘
│
┌───────────────▼─────────────────────┐
│ Application Cache │
│ (In-Memory, Request-Level) │
└───────────────┬─────────────────────┘
│
┌───────────────▼─────────────────────┐
│ Redis Cluster │
│ (Distributed Cache, 1hr TTL) │
└───────────────┬─────────────────────┘
│
┌───────────────▼─────────────────────┐
│ Database │
│ (Source of Truth) │
└─────────────────────────────────────┘
Cache Configuration¶
[cache]
cache_type = "Redis"
redis_url = "redis://redis-node-1:6379,redis-node-2:6379,redis-node-3:6379"
redis_cluster = true
# Cache TTLs
product_cache_ttl = 300 # 5 minutes
customer_cache_ttl = 600 # 10 minutes
session_cache_ttl = 86400 # 24 hours
Load Balancer Configuration¶
nginx Upstream¶
upstream rcommerce {
least_conn;
server 10.0.1.10:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.11:8080 weight=5 max_fails=3 fail_timeout=30s;
server 10.0.1.12:8080 weight=5 max_fails=3 fail_timeout=30s;
keepalive 32;
}
Health Checks¶
upstream rcommerce {
zone upstream_rcommerce 64k;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
check interval=5000 rise=2 fall=3 timeout=3000 type=http;
check_http_send "GET /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
Auto-Scaling¶
Kubernetes HPA¶
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: rcommerce-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: rcommerce
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
AWS Auto Scaling¶
# CloudFormation template
Resources:
RCommerceAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
MinSize: 2
MaxSize: 10
DesiredCapacity: 3
LaunchTemplate:
LaunchTemplateId: !Ref RCommerceLaunchTemplate
Version: !GetAtt RCommerceLaunchTemplate.LatestVersionNumber
TargetGroupARNs:
- !Ref RCommerceTargetGroup
HealthCheckType: ELB
HealthCheckGracePeriod: 300
RCommerceScalingPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref RCommerceAutoScalingGroup
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ASGAverageCPUUtilization
TargetValue: 70.0
Performance Benchmarks¶
Single Instance¶
| Instance Type | RPS | Latency p99 | Concurrent Users |
|---|---|---|---|
| 1 vCPU, 1GB | 500 | 50ms | 1,000 |
| 2 vCPU, 4GB | 2,000 | 20ms | 5,000 |
| 4 vCPU, 8GB | 5,000 | 10ms | 15,000 |
| 8 vCPU, 16GB | 12,000 | 8ms | 40,000 |
Horizontal Scaling¶
| Instances | RPS | Database Connections |
|---|---|---|
| 1 | 5,000 | 20 |
| 3 | 15,000 | 60 |
| 10 | 50,000 | 200 |
| 20 | 100,000 | 400 |
Monitoring Scaling¶
Key Metrics¶
# Request rate
rate(http_requests_total[5m])
# Response time
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# Error rate
rate(http_requests_total{status=~"5.."}[5m])
# Active connections
count(increase(http_requests_total[1m]) > 0)
# Database connections
pg_stat_activity_count{state="active"}
Alerts¶
# High request rate - scale up
- alert: HighRequestRate
expr: rate(http_requests_total[5m]) > 10000
for: 2m
labels:
severity: warning
annotations:
summary: "High request rate - consider scaling"
# High latency - investigate
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 0.1
for: 5m
labels:
severity: critical
Best Practices¶
- Start Small: Begin with vertical scaling, then horizontal
- Monitor First: Establish baselines before scaling
- Cache Aggressively: Reduce database load
- Database First: Scale database before application
- Test Load: Use load testing to find limits
- Graceful Shutdown: Handle SIGTERM for zero-downtime deploys
- Circuit Breakers: Fail fast when dependencies are down