架构概述
n8n 集群模式采用主从分布式架构,通过 Redis 消息队列实现任务调度,PostgreSQL 作为中央数据存储,实现高可用和高并发的自动化工作流处理。
核心组件
| 组件 | 角色 | 端口 | 网络 |
|---|---|---|---|
| Main Instance | Web界面 & 任务调度器 | 5678 | 公网 + 内网 |
| Redis | 消息队列代理 | 6379 | 内网 |
| PostgreSQL | 数据持久化存储 | 5432 | 内网 |
| Worker Instances | 任务执行器 | - | 内网 |
| Webhook Instance | Webhook专用处理器 | 5679 | 公网 + 内网 |
项目结构
n8n-cluster/
├── .env # 环境配置文件
├── docker-compose.yml # 主部署文件
├── configs/ # 配置目录
│ ├── redis.conf # Redis配置文件
│ └── postgres-init.sql # 数据库初始化脚本
├── data/ # 数据目录
│ ├── redis/ # Redis数据
│ ├── postgres/ # PostgreSQL数据
│ └── n8n/ # n8n共享数据
└── logs/ # 日志目录
├── n8n-main/
├── n8n-worker/
├── redis/
└── postgres/
环境配置
1. 生成安全密钥
# 生成加密密钥(32字符)
openssl rand -base64 24 | head -c 32
# 生成数据库密码
openssl rand -base64 12
# 生成Redis密码
openssl rand -base64 16
2. 环境配置文件 (.env)
vim .env
用下面的配置
# =====================
# 项目配置
# =====================
COMPOSE_PROJECT_NAME=n8n-cluster
COMPOSE_PROFILES=main,worker,webhook
# =====================
# n8n 基础配置
# =====================
N8N_VERSION=1.40.1
N8N_LOG_LEVEL=info
N8N_LOG_OUTPUT=json
N8N_HOST=your-production-domain.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://your-production-domain.com
GENERIC_TIMEZONE=Asia/Shanghai
# =====================
# 安全配置
# =====================
N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=secure_password_$(openssl rand -base64 12)
N8N_ENCRYPTION_KEY=your_32_character_encryption_key_here
N8N_EXPRESS_TRUST_PROXY=true
N8N_SECURE_COOKIE=true
# =====================
# 队列模式配置
# =====================
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
QUEUE_BULL_REDIS_PORT=6379
QUEUE_BULL_REDIS_PASSWORD=redis_password_$(openssl rand -base64 16)
QUEUE_HEALTH_CHECK_ACTIVE=true
QUEUE_STATISTICS_INTERVAL=60000
N8N_RUNNERS_ENABLED=true
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_AGE=336
# =====================
# 数据库配置
# =====================
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n_production
DB_POSTGRESDB_USER=n8n_user
DB_POSTGRESDB_PASSWORD=postgres_password_$(openssl rand -base64 16)
DB_POSTGRESDB_SSL=false
DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=false
# =====================
# 性能调优
# =====================
N8N_MEMORY_HEAP_LIMIT=4096
N8N_DIAGNOSTICS_ENABLED=true
N8N_PUBLIC_API_DISABLED=true
N8N_DISABLE_PRODUCTION_MAIN_PROCESS=false
# =====================
# 网络配置
# =====================
TRAEFIK_PUBLIC_NETWORK=traefik-public
INTERNAL_NETWORK=n8n-internal
Docker Compose 配置
vim docker-compose.yml
内容如下
version: '3.8'
x-n8n-common: &n8n-common
image: n8nio/n8n:${N8N_VERSION:-latest}
restart: unless-stopped
env_file: .env
volumes:
- ./data/n8n:/home/node/.n8n
- ./logs/n8n:/home/node/.n8n/logs
environment:
- TZ=UTC
- NODE_OPTIONS=--max-old-space-size=${N8N_MEMORY_HEAP_LIMIT:-4096}
networks:
- ${INTERNAL_NETWORK:-n8n-internal}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5678/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
x-redis-common: &redis-common
image: redis:6-alpine
restart: unless-stopped
volumes:
- ./data/redis:/data
- ./configs/redis.conf:/usr/local/etc/redis/redis.conf
- ./logs/redis:/var/log/redis
environment:
- REDIS_PASSWORD=${QUEUE_BULL_REDIS_PASSWORD}
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
networks:
- ${INTERNAL_NETWORK:-n8n-internal}
healthcheck:
test: ["CMD", "redis-cli", "-a", "${QUEUE_BULL_REDIS_PASSWORD}", "ping"]
interval: 30s
timeout: 10s
retries: 3
x-postgres-common: &postgres-common
image: postgres:15-alpine
restart: unless-stopped
volumes:
- ./data/postgres:/var/lib/postgresql/data
- ./configs/postgres-init.sql:/docker-entrypoint-initdb.d/init.sql
- ./logs/postgres:/var/log/postgresql
environment:
POSTGRES_USER: ${DB_POSTGRESDB_USER}
POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
POSTGRES_DB: ${DB_POSTGRESDB_DATABASE}
POSTGRES_INITDB_ARGS: --encoding=UTF-8 --lc-collate=C --lc-ctype=C
networks:
- ${INTERNAL_NETWORK:-n8n-internal}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_POSTGRESDB_USER} -d ${DB_POSTGRESDB_DATABASE}"]
interval: 30s
timeout: 10s
retries: 3
services:
# Redis 消息队列
redis:
<<: *redis-common
container_name: n8n-redis
ports:
- "6379:6379"
# PostgreSQL 数据库
postgres:
<<: *postgres-common
container_name: n8n-postgres
ports:
- "5432:5432"
# Main n8n 实例
n8n-main:
<<: *n8n-common
container_name: n8n-main
profiles: ["main"]
ports:
- "5678:5678"
environment:
- N8N_DISABLE_PRODUCTION_MAIN_PROCESS=false
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
# Worker 实例
n8n-worker:
<<: *n8n-common
profiles: ["worker"]
command: worker --concurrency=10
environment:
- N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
deploy:
replicas: 3
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
# Webhook 专用实例
n8n-webhook:
<<: *n8n-common
container_name: n8n-webhook
profiles: ["webhook"]
ports:
- "5679:5678"
environment:
- N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
networks:
n8n-internal:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
traefik-public:
external: true
volumes:
n8n-data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/n8n
配置文件
Redis 配置 (configs/redis.conf)
mkdir -p configs
nano configs/redis.conf
建议的配置如下:
bind 0.0.0.0
port 6379
requirepass ${REDIS_PASSWORD}
daemonize no
protected-mode yes
# 持久化配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 内存管理
maxmemory 1gb
maxmemory-policy allkeys-lru
# 性能调优
tcp-keepalive 300
timeout 0
tcp-backlog 511
# 慢查询日志
slowlog-log-slower-than 10000
slowlog-max-len 128
# 连接限制
maxclients 10000
PostgreSQL 初始化 (configs/postgres-init.sql)
vim configs/postgres-init.sql
建议如下的优化
-- n8n 数据库初始化脚本
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- 性能优化设置
ALTER SYSTEM SET shared_buffers = '1GB';
ALTER SYSTEM SET effective_cache_size = '3GB';
ALTER SYSTEM SET work_mem = '16MB';
ALTER SYSTEM SET maintenance_work_mem = '256MB';
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
ALTER SYSTEM SET wal_buffers = '16MB';
ALTER SYSTEM SET default_statistics_target = 100;
-- 创建监控用户(可选)
CREATE USER monitor WITH PASSWORD 'monitor_password';
GRANT pg_monitor TO monitor;
部署流程
1. 初始化环境
# 创建目录结构
mkdir -p {data,logs,configs}/{redis,postgres,n8n}
# 设置目录权限
chmod -R 755 data logs configs
# 生成加密密钥并更新.env
sed -i "s/your_32_character_encryption_key_here/$(openssl rand -base64 24 | head -c 32)/" .env
2. 启动基础设施
# 启动数据库和Redis
docker-compose up -d redis postgres
# 等待服务就绪
docker-compose logs -f redis postgres
# 验证连接
docker-compose exec redis redis-cli -a $REDIS_PASSWORD ping
docker-compose exec postgres psql -U $DB_POSTGRESDB_USER -d $DB_POSTGRESDB_DATABASE -c "SELECT version();"
3. 部署 n8n 服务
# 启动主实例
docker-compose --profile main up -d n8n-main
# 启动worker实例
docker-compose --profile worker up -d --scale n8n-worker=3
# 启动webhook实例(可选)
docker-compose --profile webhook up -d n8n-webhook
# 查看部署状态
docker-compose ps
4. 验证集群状态
# 检查服务健康状态
curl -u admin:password http://localhost:5678/healthz
# 检查队列状态
docker-compose exec redis redis-cli -a $REDIS_PASSWORD info keyspace
# 查看worker连接
docker-compose exec redis redis-cli -a $REDIS_PASSWORD CLIENT LIST | grep n8n
监控和维护
健康检查脚本
nano scripts/healthcheck.sh
如下内容
#!/bin/bash
# 健康检查脚本
REDIS_PASSWORD=$(grep QUEUE_BULL_REDIS_PASSWORD .env | cut -d '=' -f2)
check_service() {
local service=$1
local port=$2
if nc -z localhost $port; then
echo "✓ $service is running on port $port"
return 0
else
echo "✗ $service is not responding on port $port"
return 1
fi
}
check_redis() {
if docker-compose exec redis redis-cli -a $REDIS_PASSWORD ping | grep -q PONG; then
echo "✓ Redis is healthy"
return 0
else
echo "✗ Redis is not healthy"
return 1
fi
}
check_postgres() {
if docker-compose exec postgres pg_isready -U $DB_USER -d $DB_NAME; then
echo "✓ PostgreSQL is healthy"
return 0
else
echo "✗ PostgreSQL is not healthy"
return 1
fi
}
# 执行检查
check_service "n8n-main" 5678
check_service "Redis" 6379
check_service "PostgreSQL" 5432
check_redis
check_postgres
备份和恢复
简单备份的脚本
nano scripts/backup.sh
如下的内容
#!/bin/bash
# 备份脚本
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="./backups/$DATE"
mkdir -p $BACKUP_DIR
# 备份 PostgreSQL
docker-compose exec postgres pg_dump -U $DB_USER $DB_NAME > $BACKUP_DIR/n8n_backup.sql
# 备份 Redis
docker-compose exec redis redis-cli -a $REDIS_PASSWORD SAVE
cp ./data/redis/dump.rdb $BACKUP_DIR/redis_backup.rdb
# 备份 n8n 配置
tar -czf $BACKUP_DIR/n8n_config.tar.gz ./data/n8n/
echo "Backup completed: $BACKUP_DIR"
性能调优
Worker 并发配置
根据 CPU 核心数调整 worker 数量:
# 获取CPU核心数
CPU_CORES=$(nproc)
# 动态调整worker数量
WORKER_COUNT=$((CPU_CORES * 2))
docker-compose --profile worker up -d --scale n8n-worker=$WORKER_COUNT
数据库性能优化
-- 为常用查询添加索引
CREATE INDEX IF NOT EXISTS idx_executions_workflow_id ON executions (workflowId);
CREATE INDEX IF NOT EXISTS idx_executions_status ON executions (status);
CREATE INDEX IF NOT EXISTS idx_executions_created_at ON executions (createdAt);
故障排除
常见问题解决
-
加密密钥不匹配
# 统一所有实例的加密密钥 grep N8N_ENCRYPTION_KEY .env -
Redis 连接问题
# 检查Redis连接 docker-compose exec redis redis-cli -a $REDIS_PASSWORD ping -
数据库连接问题
# 检查数据库连接 docker-compose exec postgres psql -U $DB_USER -d $DB_NAME -c "\conninfo"
日志分析
# 实时查看日志
docker-compose logs -f --tail=100
# 查看特定服务日志
docker-compose logs n8n-main
docker-compose logs n8n-worker
docker-compose logs redis
docker-compose logs postgres
# 过滤不同级别
docker-compose logs n8n-worker | grep -i error
# 监控队列性能
docker-compose exec redis redis-cli -a $REDIS_PASSWORD info stats | grep instantaneous_ops_per_sec