🚀 Scaling n8n
Khi workflow executions tăng, single instance không đủ. Bài này covers queue mode, horizontal scaling, và high availability setup để handle production workloads.
Scaling Overview
When to Scale:
Text
1SCALING INDICATORS2──────────────────3 4👁️ Watch for:5├── Response time increasing6├── Executions taking longer7├── Queue backing up8├── CPU consistently > 80%9├── Memory pressure10└── Timeouts/failures increasing11 12📊 Metrics thresholds:13├── > 1000 executions/hour14├── > 50 concurrent workflows15├── > 10 long-running workflows16└── Peak webhook traffic spikesScaling Strategies:
Text
1SCALING OPTIONS2───────────────3 4VERTICAL (Scale Up)5├── More CPU6├── More RAM7├── Faster disk8├── Simpler setup9├── Limited ceiling10└── Single point of failure11 12HORIZONTAL (Scale Out)13├── Multiple instances14├── Load balancing15├── Queue mode required16├── Higher ceiling17├── More complex18└── Better availabilityQueue Mode Architecture
How Queue Mode Works:
Text
1QUEUE MODE ARCHITECTURE2───────────────────────3 4 ┌──────────────┐5 │ Trigger │6 │ (Webhook/ │7 │ Schedule) │8 └──────┬───────┘9 │10 ▼11 ┌──────────────┐12 │ Main n8n │13 │ (Queue jobs)│14 └──────┬───────┘15 │16 ▼17 ┌──────────────┐18 │ Redis │19 │ (Queue) │20 └──────┬───────┘21 │22 ┌──────────┼──────────┐23 ▼ ▼ ▼24 ┌─────────┐┌─────────┐┌─────────┐25 │ Worker 1││ Worker 2││ Worker 3│26 └─────────┘└─────────┘└─────────┘27 │ │ │28 └──────────┼──────────┘29 ▼30 ┌──────────────┐31 │ PostgreSQL │32 │ (Results) │33 └──────────────┘Enable Queue Mode:
Bash
1# Main instance (receives triggers)2N8N_MODE=main3QUEUE_BULL_REDIS_HOST=redis4QUEUE_BULL_REDIS_PORT=63795QUEUE_HEALTH_CHECK_ACTIVE=true6 7# Worker instances (process executions)8N8N_MODE=worker9QUEUE_BULL_REDIS_HOST=redis10QUEUE_BULL_REDIS_PORT=637911EXECUTIONS_MODE=queueDocker Compose: Queue Mode
Complete Stack:
yaml
1version: '3.8'2 3services:4 # PostgreSQL Database5 postgres:6 image: postgres:15-alpine7 restart: always8 environment:9 POSTGRES_USER: n8n10 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}11 POSTGRES_DB: n8n12 volumes:13 - postgres_data:/var/lib/postgresql/data14 healthcheck:15 test: ["CMD-SHELL", "pg_isready -U n8n"]16 interval: 10s17 timeout: 5s18 retries: 519 20 # Redis Queue21 redis:22 image: redis:7-alpine23 restart: always24 command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru25 volumes:26 - redis_data:/data27 healthcheck:28 test: ["CMD", "redis-cli", "ping"]29 interval: 10s30 timeout: 5s31 retries: 532 33 # Main n8n (handles triggers, UI)34 n8n-main:35 image: n8nio/n8n:latest36 restart: always37 environment:38 # Database39 - DB_TYPE=postgresdb40 - DB_POSTGRESDB_HOST=postgres41 - DB_POSTGRESDB_PORT=543242 - DB_POSTGRESDB_DATABASE=n8n43 - DB_POSTGRESDB_USER=n8n44 - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}45 46 # Queue mode47 - EXECUTIONS_MODE=queue48 - QUEUE_BULL_REDIS_HOST=redis49 - QUEUE_BULL_REDIS_PORT=637950 - QUEUE_HEALTH_CHECK_ACTIVE=true51 52 # Encryption53 - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}54 55 # URLs56 - N8N_HOST=n8n.yourdomain.com57 - N8N_PROTOCOL=https58 - WEBHOOK_URL=https://n8n.yourdomain.com59 60 # Metrics61 - N8N_METRICS=true62 ports:63 - "5678:5678"64 depends_on:65 postgres:66 condition: service_healthy67 redis:68 condition: service_healthy69 volumes:70 - n8n_data:/home/node/.n8n71 72 # Worker 173 n8n-worker-1:74 image: n8nio/n8n:latest75 restart: always76 command: worker77 environment:78 - DB_TYPE=postgresdb79 - DB_POSTGRESDB_HOST=postgres80 - DB_POSTGRESDB_PORT=543281 - DB_POSTGRESDB_DATABASE=n8n82 - DB_POSTGRESDB_USER=n8n83 - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}84 - EXECUTIONS_MODE=queue85 - QUEUE_BULL_REDIS_HOST=redis86 - QUEUE_BULL_REDIS_PORT=637987 - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}88 # Worker-specific89 - QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD=3000090 - N8N_CONCURRENCY_PRODUCTION_LIMIT=1091 depends_on:92 - postgres93 - redis94 - n8n-main95 volumes:96 - n8n_data:/home/node/.n8n97 98 # Worker 299 n8n-worker-2:100 image: n8nio/n8n:latest101 restart: always102 command: worker103 environment:104 - DB_TYPE=postgresdb105 - DB_POSTGRESDB_HOST=postgres106 - DB_POSTGRESDB_PORT=5432107 - DB_POSTGRESDB_DATABASE=n8n108 - DB_POSTGRESDB_USER=n8n109 - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}110 - EXECUTIONS_MODE=queue111 - QUEUE_BULL_REDIS_HOST=redis112 - QUEUE_BULL_REDIS_PORT=6379113 - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}114 - QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD=30000115 - N8N_CONCURRENCY_PRODUCTION_LIMIT=10116 depends_on:117 - postgres118 - redis119 - n8n-main120 volumes:121 - n8n_data:/home/node/.n8n122 123volumes:124 postgres_data:125 redis_data:126 n8n_data:Worker Configuration
Concurrency Settings:
Bash
1# Concurrent executions per worker2N8N_CONCURRENCY_PRODUCTION_LIMIT=10 # Default: 53 4# Concurrent polling5QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD=300006 7# Job timeouts8EXECUTIONS_TIMEOUT=3600 # 1 hour max9 10# Retry settings11EXECUTIONS_RETRY_MAX_COUNT=5Worker Resource Allocation:
yaml
1# docker-compose with resource limits2n8n-worker-1:3 image: n8nio/n8n:latest4 command: worker5 deploy:6 resources:7 limits:8 cpus: '2.0'9 memory: 2G10 reservations:11 cpus: '1.0'12 memory: 1G13 # ... other configScale Workers Dynamically:
Bash
1# Scale to 5 workers2docker-compose up -d --scale n8n-worker=53 4# Check worker count5docker-compose ps | grep worker6 7# Scale down8docker-compose up -d --scale n8n-worker=2Load Balancing
Nginx Load Balancer:
nginx
1# /etc/nginx/nginx.conf2 3upstream n8n_cluster {4 least_conn; # or round-robin5 6 server n8n-main-1:5678;7 server n8n-main-2:5678;8 server n8n-main-3:5678;9 10 # Health checks11 keepalive 32;12}13 14server {15 listen 443 ssl http2;16 server_name n8n.yourdomain.com;17 18 ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem;19 ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem;20 21 location / {22 proxy_pass http://n8n_cluster;23 proxy_http_version 1.1;24 proxy_set_header Upgrade $http_upgrade;25 proxy_set_header Connection "upgrade";26 proxy_set_header Host $host;27 proxy_set_header X-Real-IP $remote_addr;28 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;29 proxy_set_header X-Forwarded-Proto $scheme;30 31 # Timeouts for long executions32 proxy_connect_timeout 300;33 proxy_send_timeout 300;34 proxy_read_timeout 300;35 }36}Sticky Sessions (if needed):
nginx
1upstream n8n_cluster {2 ip_hash; # Sticky sessions by IP3 4 server n8n-main-1:5678;5 server n8n-main-2:5678;6}High Availability Setup
HA Architecture:
Text
1HIGH AVAILABILITY SETUP2───────────────────────3 4 ┌─────────────┐5 │ Load │6 │ Balancer │7 └──────┬──────┘8 │9 ┌───────────────┼───────────────┐10 ▼ ▼ ▼11 ┌─────────┐ ┌─────────┐ ┌─────────┐12 │ Main 1 │ │ Main 2 │ │ Main 3 │13 └────┬────┘ └────┬────┘ └────┬────┘14 │ │ │15 └──────────────┼──────────────┘16 │17 ┌─────┴─────┐18 │ Redis │19 │ Cluster │20 └─────┬─────┘21 │22 ┌──────────────┼──────────────┐23 ▼ ▼ ▼24 ┌─────────┐ ┌─────────┐ ┌─────────┐25 │Worker 1 │ │Worker 2 │ │Worker 3 │26 └────┬────┘ └────┬────┘ └────┬────┘27 │ │ │28 └──────────────┼──────────────┘29 │30 ┌─────┴─────┐31 │ PostgreSQL│32 │ Primary │33 └─────┬─────┘34 │35 ┌─────┴─────┐36 │ PostgreSQL│37 │ Replica │38 └───────────┘Redis Cluster Setup:
yaml
1# Redis Sentinel for HA2services:3 redis-master:4 image: redis:7-alpine5 command: redis-server --appendonly yes6 7 redis-slave-1:8 image: redis:7-alpine9 command: redis-server --slaveof redis-master 637910 11 redis-slave-2:12 image: redis:7-alpine13 command: redis-server --slaveof redis-master 637914 15 redis-sentinel-1:16 image: redis:7-alpine17 command: redis-sentinel /etc/redis/sentinel.conf18 volumes:19 - ./sentinel.conf:/etc/redis/sentinel.confSentinel Config:
conf
1# sentinel.conf2sentinel monitor mymaster redis-master 6379 23sentinel down-after-milliseconds mymaster 50004sentinel failover-timeout mymaster 600005sentinel parallel-syncs mymaster 1Kubernetes Deployment
n8n Kubernetes Manifest:
yaml
1# n8n-deployment.yaml2apiVersion: apps/v13kind: Deployment4metadata:5 name: n8n-main6spec:7 replicas: 28 selector:9 matchLabels:10 app: n8n11 component: main12 template:13 metadata:14 labels:15 app: n8n16 component: main17 spec:18 containers:19 - name: n8n20 image: n8nio/n8n:latest21 ports:22 - containerPort: 567823 env:24 - name: DB_TYPE25 value: "postgresdb"26 - name: DB_POSTGRESDB_HOST27 value: "postgres-service"28 - name: EXECUTIONS_MODE29 value: "queue"30 - name: QUEUE_BULL_REDIS_HOST31 value: "redis-service"32 - name: N8N_ENCRYPTION_KEY33 valueFrom:34 secretKeyRef:35 name: n8n-secrets36 key: encryption-key37 resources:38 requests:39 memory: "512Mi"40 cpu: "500m"41 limits:42 memory: "2Gi"43 cpu: "2"44 livenessProbe:45 httpGet:46 path: /healthz47 port: 567848 initialDelaySeconds: 3049 periodSeconds: 1050 readinessProbe:51 httpGet:52 path: /healthz53 port: 567854 initialDelaySeconds: 555 periodSeconds: 556---57# Worker deployment58apiVersion: apps/v159kind: Deployment60metadata:61 name: n8n-worker62spec:63 replicas: 364 selector:65 matchLabels:66 app: n8n67 component: worker68 template:69 metadata:70 labels:71 app: n8n72 component: worker73 spec:74 containers:75 - name: n8n-worker76 image: n8nio/n8n:latest77 command: ["n8n", "worker"]78 env:79 - name: DB_TYPE80 value: "postgresdb"81 - name: EXECUTIONS_MODE82 value: "queue"83 # ... same env vars as main84 resources:85 requests:86 memory: "512Mi"87 cpu: "500m"88 limits:89 memory: "2Gi"90 cpu: "2"Horizontal Pod Autoscaler:
yaml
1# hpa.yaml2apiVersion: autoscaling/v23kind: HorizontalPodAutoscaler4metadata:5 name: n8n-worker-hpa6spec:7 scaleTargetRef:8 apiVersion: apps/v19 kind: Deployment10 name: n8n-worker11 minReplicas: 212 maxReplicas: 1013 metrics:14 - type: Resource15 resource:16 name: cpu17 target:18 type: Utilization19 averageUtilization: 7020 - type: Resource21 resource:22 name: memory23 target:24 type: Utilization25 averageUtilization: 80Performance Optimization
Queue Optimization:
Bash
1# Increase concurrency for light workflows2N8N_CONCURRENCY_PRODUCTION_LIMIT=203 4# Decrease for heavy/memory-intensive workflows5N8N_CONCURRENCY_PRODUCTION_LIMIT=56 7# Job timeout (prevent stuck jobs)8EXECUTIONS_TIMEOUT=1800 # 30 minutes9EXECUTIONS_TIMEOUT_MAX=7200 # 2 hours absolute maxRedis Optimization:
Bash
1# redis.conf2maxmemory 2gb3maxmemory-policy allkeys-lru4 5# Persistence6appendonly yes7appendfsync everysec8 9# Connections10tcp-keepalive 30011timeout 012 13# Performance14io-threads 415io-threads-do-reads yesPostgreSQL Optimization:
SQL
1-- Connection pooling2-- Use PgBouncer for many workers34-- Indexes for execution queries5CREATE INDEX CONCURRENTLY idx_execution_started 6ON execution_entity("startedAt" DESC);78CREATE INDEX CONCURRENTLY idx_execution_workflow_status 9ON execution_entity("workflowId", finished);1011-- Vacuum settings12ALTER TABLE execution_entity SET (autovacuum_vacuum_scale_factor = 0.05);Monitoring Scaled Setup
Queue Metrics:
Bash
1#!/bin/bash2# queue-stats.sh3 4# Check Redis queue depth5docker exec redis redis-cli LLEN bull:jobs:wait6docker exec redis redis-cli LLEN bull:jobs:active7docker exec redis redis-cli LLEN bull:jobs:delayed8docker exec redis redis-cli LLEN bull:jobs:failedWorker Health:
Bash
1#!/bin/bash2# worker-health.sh3 4echo "=== Worker Status ==="5docker-compose ps | grep worker6 7echo ""8echo "=== Worker Logs (last errors) ==="9docker-compose logs --tail=50 n8n-worker-1 | grep -i error10 11echo ""12echo "=== Queue Depth ==="13docker exec redis redis-cli LLEN bull:jobs:waitGrafana Dashboard Additions:
Text
1Queue Panels:2├── Queue Depth (wait + active)3├── Processing Rate (jobs/sec)4├── Worker Count5├── Job Duration Distribution6└── Failed Jobs RateTroubleshooting Scale Issues
Queue Backlog Growing:
Text
1Problem: Jobs queuing faster than processing2 3Solutions:41. Add more workers52. Increase concurrency per worker63. Optimize slow workflows74. Check for stuck jobsWorkers Crashing:
Text
1Problem: Workers running out of memory2 3Solutions:41. Reduce concurrency52. Add resource limits63. Check for memory leaks in workflows74. Split heavy workflowsDatabase Bottleneck:
Text
1Problem: DB connections maxed out2 3Solutions:41. Implement connection pooling52. Reduce worker count63. Add read replicas74. Optimize queriesBài Tập Thực Hành
Scaling Challenge
Implement scaled n8n:
- Set up queue mode with Redis
- Deploy 3 workers
- Configure load balancing (nginx)
- Test failover (stop one worker)
- Monitor queue depth
- Load test with many webhook requests
Master n8n scaling! 🚀
Scaling Checklist
Production Checklist
Before going to scaled production:
- Queue mode enabled and tested
- Redis properly configured with persistence
- Workers have resource limits
- Load balancer health checks working
- Database connection pooling in place
- Monitoring covers all components
- Backup strategy includes Redis
- Failover tested and documented
Key Takeaways
Remember
- 📊 Queue mode required - For horizontal scaling
- 🔄 Workers are stateless - Scale easily
- ⚖️ Balance resources - Don't over-provision
- 🏥 Health checks - Essential for HA
- 📈 Monitor everything - Queue, workers, database
Tổng Kết Khóa Học
Chúc mừng! Bạn đã hoàn thành n8n Deployment course. Bây giờ bạn có thể:
- ✅ Deploy n8n với Docker/Cloud platforms
- ✅ Configure production environment
- ✅ Secure your instance properly
- ✅ Manage users và permissions
- ✅ Monitor và alert on issues
- ✅ Scale for production workloads
Next steps: Deploy your production n8n và build amazing automations! 🎉
