n8n 集群模式生产环境部署指南

254 阅读4分钟

架构概述

n8n 集群模式采用主从分布式架构,通过 Redis 消息队列实现任务调度,PostgreSQL 作为中央数据存储,实现高可用和高并发的自动化工作流处理。

核心组件

组件角色端口网络
Main InstanceWeb界面 & 任务调度器5678公网 + 内网
Redis消息队列代理6379内网
PostgreSQL数据持久化存储5432内网
Worker Instances任务执行器-内网
Webhook InstanceWebhook专用处理器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);

故障排除

常见问题解决

  1. 加密密钥不匹配

    # 统一所有实例的加密密钥
    grep N8N_ENCRYPTION_KEY .env
    
  2. Redis 连接问题

    # 检查Redis连接
    docker-compose exec redis redis-cli -a $REDIS_PASSWORD ping
    
  3. 数据库连接问题

    # 检查数据库连接
    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