7 분 소요

Summary

n8n 을 셀프호스팅하다 보면 어느 순간 “실행이 한 프로세스에 다 몰려서 무거운 워크플로우 하나가 전체를 막는” 상황을 만나요. 이걸 푸는 게 큐 모드(queue mode) 입니다. 메인 인스턴스는 UI·API·트리거만 맡고, 실제 실행은 별도 워커(worker) 들이 Redis 큐에서 꺼내 처리하는 구조에요.

이 글에서는 기본인 일반 모드(regular)큐 모드 를 세팅 방법부터 장단점까지 비교하고, 큐모드에서 자주 막히는 지점인 바이너리 데이터와 S3 이야기를 정리합니다. 그리고 S3 없이도 큐모드를 굴리는 방법까지 같이 다뤄볼게요.

💡 이 글에서 다루는 것

  • 일반 모드 / 큐 모드의 구조 차이 (한 그림으로)
  • 각각의 세팅 방법 (env 변수, 워커·웹훅 프로세서, docker-compose 예시)
  • 두 모드의 장단점 비교표
  • 큐모드가 바이너리 데이터에 S3 를 요구하는 진짜 이유
  • S3 없이 database 모드로 구축하는 법과 그 트레이드오프



1. 한 그림으로 — 일반 모드 vs 큐 모드

먼저 두 모드가 어떻게 다른지 구조부터 잡고 갈게요.

일반 모드 는 n8n 프로세스 하나가 전부 다 합니다. UI 를 띄우고, API 를 받고, 스케줄/웹훅 트리거를 감시하고, 워크플로우 실행까지 같은 프로세스 안에서 처리해요.

[ n8n (main) ]  ← UI · API · 트리거 · 실행을 전부 한 프로세스에서
        │
   [ PostgreSQL ]

큐 모드 는 역할을 쪼갭니다. 메인은 “받기”만 하고, 실행은 Redis 큐를 거쳐 워커들에게 분산돼요.

                 [ Redis (Bull 큐) ]
                  ▲             │
                  │ enqueue     │ dequeue
        [ n8n (main) ]    [ worker 1 ]
        UI·API·트리거      [ worker 2 ]
                  │        [ worker N ]
                  └──────┬────────┘
                  [ PostgreSQL (공유) ]

핵심은 메인과 워커가 서로 다른 프로세스(보통 다른 컨테이너, 때로는 다른 머신)라는 점이에요. 이 “분리” 가 큐모드의 모든 장점과 단점의 출발점입니다. 나중에 S3 이야기도 전부 여기서 나와요.



2. 일반(regular) 모드 세팅

사실 일반 모드는 “세팅” 이랄 게 거의 없어요. n8n 의 기본값이 일반 모드라서, 아무 설정 없이 띄우면 그대로 일반 모드입니다.

docker run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -e DB_TYPE=postgresdb \
  -e DB_POSTGRESDB_HOST=postgres \
  -e DB_POSTGRESDB_DATABASE=n8n \
  -e DB_POSTGRESDB_USER=n8n \
  -e DB_POSTGRESDB_PASSWORD=<DB_PASSWORD> \
  -e N8N_ENCRYPTION_KEY=<N8N_ENCRYPTION_KEY> \
  docker.n8n.io/n8nio/n8n

명시적으로 모드를 박고 싶다면 이렇게 둡니다.

-e EXECUTIONS_MODE=regular

✅ 소규모 팀, 워크플로우 수십 개, 동시 실행이 몇 개 수준이면 일반 모드로 충분합니다. 운영 부담이 가장 작아요. 굳이 Redis 를 얹을 이유가 없어요.



3. 큐(queue) 모드 세팅

큐 모드는 최소 세 덩어리가 필요해요.

  • Redis — 실행 작업을 담아두는 큐(내부적으로 Bull 사용)
  • 공유 PostgreSQL — 메인·워커가 같은 DB 를 봐야 함 (PostgreSQL 13+ 권장)
  • 메인 1개 + 워커 N개 — 같은 암호화 키, 같은 Redis, 같은 DB 를 공유

여기서 가장 자주 깜빡하는 게 N8N_ENCRYPTION_KEY 를 모든 인스턴스에서 동일하게 맞추는 거예요. 이게 어긋나면 워커가 자격증명을 복호화하지 못해서 실행이 줄줄이 실패합니다.


3-1. 공통 env (메인·워커·웹훅 전부)

export EXECUTIONS_MODE=queue
export N8N_ENCRYPTION_KEY=<N8N_ENCRYPTION_KEY>   # 모든 인스턴스 동일

# Redis 연결
export QUEUE_BULL_REDIS_HOST=redis
export QUEUE_BULL_REDIS_PORT=6379
export QUEUE_BULL_REDIS_PASSWORD=<REDIS_PASSWORD>
export QUEUE_BULL_REDIS_DB=0

# 공유 PostgreSQL
export DB_TYPE=postgresdb
export DB_POSTGRESDB_HOST=postgres
export DB_POSTGRESDB_DATABASE=n8n
export DB_POSTGRESDB_USER=n8n
export DB_POSTGRESDB_PASSWORD=<DB_PASSWORD>

위 블록은 메인이든 워커든 똑같이 들어갑니다. 차이는 “어떤 명령으로 띄우느냐” 뿐이에요.


3-2. 메인 인스턴스

메인은 평소처럼 기동하면 됩니다. UI·API·트리거를 담당해요.

n8n start

웹훅 트래픽이 많아서 웹훅 처리까지 따로 떼고 싶으면, 메인에서 프로덕션 웹훅 처리를 끄고 별도 웹훅 프로세서로 넘길 수 있어요.

export N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true


3-3. 워커

실제 실행을 담당하는 주인공이에요. n8n worker 로 띄웁니다.

n8n worker --concurrency=10

--concurrency 는 워커 하나가 동시에 처리할 실행 개수예요. 지정하지 않으면 기본값은 10 입니다. 워커는 그냥 컨테이너를 더 띄우면 수평으로 늘어나요. 부하가 커지면 워커 수를 늘리는 게 큐모드의 기본 스케일링 방법입니다.

워커에 헬스체크 엔드포인트를 열어두면 오케스트레이터(K8s 등)가 살아있는지 확인할 수 있어요.

export QUEUE_HEALTH_CHECK_ACTIVE=true


3-4. 웹훅 프로세서 (선택)

웹훅 수신을 전담하는 프로세스도 따로 둘 수 있어요. 메인에서 N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true 를 켰다면 이 프로세스가 웹훅을 받습니다.

n8n webhook


3-5. docker-compose 로 묶기

위 조각들을 한 파일로 모으면 이런 모양이 됩니다. 바이너리 데이터 모드는 일단 S3 없이 가는 database 로 둘게요 (이유는 6장에서 설명).

x-n8n-common: &n8n-common
  image: docker.n8n.io/n8nio/n8n
  environment:
    - EXECUTIONS_MODE=queue
    - N8N_ENCRYPTION_KEY=<N8N_ENCRYPTION_KEY>
    - QUEUE_BULL_REDIS_HOST=redis
    - QUEUE_BULL_REDIS_PORT=6379
    - QUEUE_BULL_REDIS_PASSWORD=<REDIS_PASSWORD>
    - DB_TYPE=postgresdb
    - DB_POSTGRESDB_HOST=postgres
    - DB_POSTGRESDB_DATABASE=n8n
    - DB_POSTGRESDB_USER=n8n
    - DB_POSTGRESDB_PASSWORD=<DB_PASSWORD>
    - N8N_DEFAULT_BINARY_DATA_MODE=database
  depends_on:
    - postgres
    - redis

services:
  postgres:
    image: postgres:16
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=<DB_PASSWORD>
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7
    command: ["redis-server", "--requirepass", "<REDIS_PASSWORD>"]

  n8n-main:
    <<: *n8n-common
    command: start
    ports:
      - "5678:5678"

  n8n-worker:
    <<: *n8n-common
    command: worker --concurrency=10
    # docker compose up --scale n8n-worker=3 으로 워커를 늘릴 수 있어요.

volumes:
  pgdata:

⚠️ 위 &n8n-common 의 env 가 메인·워커에 그대로 상속돼요. 그래서 암호화 키·Redis·DB 가 자동으로 동일하게 맞춰집니다. 이 공유가 큐모드의 전제 조건이에요.



4. 장단점 비교

두 모드를 한 표로 정리하면 다음과 같아요.

항목 일반 모드 (regular) 큐 모드 (queue)
구성 요소 n8n + DB n8n 메인 + 워커 N + Redis + 공유 DB
스케일링 수직(스펙 업) 위주 수평(워커 추가)으로 확장
동시 실행 처리 한 프로세스가 다 떠안음 워커들로 분산
장애 격리 무거운 실행 하나가 전체를 막을 수 있음 워커가 죽어도 메인·다른 워커는 살아있음
운영 난이도 낮음 (얹을 게 없음) 높음 (Redis·워커·키 동기화 관리)
바이너리 데이터 로컬 파일시스템 그대로 OK filesystem 모드 불가 → S3 또는 database 필요
HA(다중 메인) 불가 가능하지만 Enterprise 전용
추천 규모 소~중 중~대, 동시 실행 많음

큐모드의 장점 을 한 줄로 줄이면 “실행을 수평으로 늘려서, 무거운 워크플로우가 다른 워크플로우를 막지 않게 만드는 것” 이에요. 트래픽이 튀어도 워커만 더 붙이면 됩니다.

단점 은 운영 복잡도예요. Redis 가 새 의존성으로 들어오고, 암호화 키·Redis·DB 를 모든 인스턴스에서 똑같이 맞춰야 하고, 뒤에서 설명할 바이너리 데이터 처리도 따로 신경 써야 해요. 그래서 “동시 실행이 별로 없는데 그냥 멋있어 보여서” 큐모드를 켜는 건 비추천드립니다.



5. 왜 큐모드는 S3 를 (사실상) 써야 하나

여기가 이 글의 핵심이에요. 큐모드를 켜자마자 사람들이 가장 많이 밟는 지점이 바로 바이너리 데이터 입니다.

n8n 에서 “바이너리 데이터” 는 워크플로우가 다루는 파일이에요. HTTP 로 받은 이미지, 업로드된 PDF, 변환 중인 엑셀 같은 것들이죠. n8n 은 이 파일을 실행 데이터(JSON)와 분리해서 어딘가에 저장해 둡니다.

이걸 저장하는 방식이 바이너리 데이터 모드 이고, 세 가지가 있어요.

모드 저장 위치 비고
default (메모리/database) 메모리 → DB 에 함께 저장 큐모드에서 권장되는 기본
filesystem 실행한 프로세스의 로컬 디스크 큐모드에서 지원 안 됨
s3 S3 호환 외부 스토리지 큐모드 대규모에 적합, Enterprise 라이선스

문제는 filesystem 모드예요. 이 모드는 워크플로우를 실행한 그 프로세스의 로컬 디스크 에 파일을 씁니다. 일반 모드에서는 메인 하나가 다 처리하니 아무 문제가 없어요. 자기가 쓰고 자기가 읽으니까요.

그런데 큐모드에서는 상황이 달라집니다. 1장에서 본 것처럼 워커들은 서로 다른 프로세스(다른 컨테이너/머신) 예요.

  • worker-1 이 파일을 받아서 자기 로컬 디스크에 씀
  • 다음 단계 실행이 worker-2 로 가거나, 메인이 그 파일을 결과로 보여주려 함
  • 그런데 worker-2 와 메인은 worker-1 의 로컬 디스크를 들여다볼 수 없음 → 파일을 못 찾음

그래서 n8n 은 아예 큐모드 + filesystem 조합을 지원하지 않는다 고 못 박아 뒀어요. 공식 문서 표현 그대로:

n8n doesn’t support queue mode with binary data storage in filesystem.

결국 큐모드에서 바이너리 파일을 다루려면, 메인과 모든 워커가 똑같이 접근할 수 있는 공유 저장소 가 필요해요. 그 답으로 가장 깔끔한 게 S3 입니다. 워커가 어디에 떠 있든 같은 버킷에 쓰고 같은 버킷에서 읽으니까요. 게다가 디스크 용량 걱정 없이 무한히 늘어나죠.

S3 외부 스토리지 세팅은 이렇게 들어갑니다.

export N8N_AVAILABLE_BINARY_DATA_MODES=filesystem,s3
export N8N_DEFAULT_BINARY_DATA_MODE=s3

export N8N_EXTERNAL_STORAGE_S3_HOST=s3.ap-northeast-2.amazonaws.com
export N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME=my-n8n-binary
export N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION=ap-northeast-2
export N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY=<AWS_ACCESS_KEY_ID>
export N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET=<AWS_SECRET_ACCESS_KEY>

🚨 S3 외부 스토리지는 Enterprise 라이선스 기능 이에요. 라이선스 키가 만료되면 S3 버킷에서 읽기는 되지만 쓰기는 막힙니다. 엔터프라이즈를 쓰신다니 이 부분은 그대로 활용하시면 돼요.

정리하면 — 큐모드가 S3 를 “요구” 하는 게 아니라, 큐모드는 프로세스가 분리돼 있어서 로컬 디스크를 공유 못 하고, 그래서 파일을 다루려면 공유 저장소가 필수인데, 그 공유 저장소로 가장 자연스러운 선택지가 S3 인 거예요.



6. S3 없이 큐모드를 구축하는 방법

그럼 S3 가 없으면 큐모드를 못 쓰냐? 그건 아니에요. 핵심은 “공유 저장소” 였고, 메인과 워커가 이미 공유하는 저장소가 하나 더 있죠 — PostgreSQL 입니다.

바이너리 데이터 모드를 database 로 두면, 파일을 로컬 디스크가 아니라 공유 DB 에 함께 저장 해요. 모든 워커와 메인이 같은 Postgres 를 보니까, 누가 쓰든 누구나 읽을 수 있습니다. S3 도, Enterprise 라이선스도 필요 없어요.

export N8N_DEFAULT_BINARY_DATA_MODE=database

공식 문서도 “큐모드를 쓰면 이 값을 database 로 바꾸라” 고 안내하고 있어요. 그래서 위 5장 docker-compose 예시에서도 기본값으로 database 를 박아둔 거예요.

다만 트레이드오프가 분명해요.

⚠️ database 모드의 한계

  • 파일이 전부 DB 로 들어가서 DB 용량이 빠르게 불어납니다. 큰 파일을 자주 다루면 더 심해요.
  • DB I/O·메모리 부담이 커져서, 대용량 파일에서는 S3 대비 느리고 무겁습니다.
  • 실행 데이터 정리(pruning) 정책을 같이 잡아두지 않으면 DB 가 계속 커져요.

그래서 권장은 이렇게 정리돼요.

  • 파일을 거의 안 다루거나, 다뤄도 작고 가끔database 모드로 충분. S3 없이 큐모드 OK.
  • 이미지·PDF·대용량 파일을 자주, 많이 → S3(외부 스토리지) 가 정답. Enterprise 라이선스가 있다면 이쪽을 권장드려요.

참고로 “그럼 NFS 같은 공유 디스크를 워커들에 마운트해서 filesystem 모드를 쓰면 되지 않냐” 는 아이디어가 나올 수 있는데, n8n 은 큐모드 + filesystem 조합 자체를 지원하지 않는다 고 명시해 둬서 권장하지 않아요. 공유 저장소가 필요하면 database 아니면 s3, 이 둘 중에서 고르는 게 안전합니다.



7. 정리

마지막으로 의사결정 흐름만 짧게 짚을게요.

  • 동시 실행이 적고 운영을 단순하게 → 일반 모드.
  • 동시 실행이 많고 수평 확장·장애 격리가 필요 → 큐 모드 (Redis + 워커 + 공유 DB + 동일 암호화 키).
  • 큐모드에서 파일을 다룬다면 → filesystem 은 못 쓰니까,
    • 작고 가끔이면 → database 모드 (S3·라이선스 불필요)
    • 크고 자주면 → S3 외부 스토리지 (Enterprise)

큐모드의 S3 이야기는 “n8n 이 별나서” 가 아니라, 실행을 여러 프로세스로 쪼갠 순간 로컬 디스크를 공유할 수 없게 되는 분산 시스템의 당연한 결과예요. 그 한 줄만 기억하면 바이너리 데이터 설정에서 헤맬 일이 없어요.

일단 오늘은 여기까지…..
다음 글에서는 큐모드 워커를 K8s 로 올릴 때의 HPA·헬스체크 구성을 정리해볼게요.