성능 최적화 — 대용량 데이터와 고속 실행
10건으로 테스트하면 잘 돌아간다. 그런데 10,000건을 넣으면? 메모리 부족, 타임아웃, API 제한... 프로덕션의 현실이 시작된다.
성능 병목 진단
흔한 병목 지점
| 증상 | 원인 | 해결 |
|---|---|---|
| 메모리 초과 | 대용량 바이너리 데이터 | Filesystem Binary 모드 |
| 실행 시간 초과 | 직렬 API 호출 | 병렬 처리 + 배치 |
| 429 에러 다수 | API Rate Limit 초과 | Split In Batches + Wait |
| DB 느려짐 | 실행 데이터 누적 | Pruning 설정 |
| 동시 실행 충돌 | 동일 워크플로우 중복 실행 | Queue Mode |
메모리 최적화
Binary Data 모드
기본적으로 n8n은 바이너리 데이터(파일)를 메모리에 저장한다. 대용량 파일 처리 시 메모리 폭증의 원인이 된다.
# docker-compose.yml
environment:
# 바이너리를 파일 시스템에 저장 (메모리 절약)
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem
- N8N_BINARY_DATA_STORAGE_PATH=/home/node/.n8n/binary-data
| 모드 | 저장 위치 | 메모리 사용 | 속도 |
|---|---|---|---|
default | 메모리 + DB | 높음 | 빠름 |
filesystem | 디스크 | 낮음 | 보통 |
Docker 메모리 제한
services:
n8n:
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 512M
실행 데이터 관리 (Pruning)
모든 워크플로우 실행 데이터가 DB에 쌓이면 디스크와 성능을 잡아먹는다.
environment:
# 자동 정리 활성화
- EXECUTIONS_DATA_PRUNE=true
# 720시간(30일) 이전 데이터 삭제
- EXECUTIONS_DATA_MAX_AGE=720
# 성공한 실행만 정리 (에러는 보존)
- EXECUTIONS_DATA_PRUNE_TIMEOUT=3600
실행 데이터 저장 최적화
environment:
# 수동 실행 데이터 저장 여부
- EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=false
# 성공한 자동 실행 저장 여부
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=all # all | none
# 에러 실행 저장 여부
- EXECUTIONS_DATA_SAVE_ON_ERROR=all # 반드시 all
DB 튜닝: SQLite → PostgreSQL
프로덕션에서는 PostgreSQL이 필수다.
SQLite vs PostgreSQL
| 특성 | SQLite | PostgreSQL |
|---|---|---|
| 동시성 | 단일 쓰기 잠금 | 다중 동시 쓰기 |
| 데이터 크기 | ~1GB 이상 시 성능 저하 | 수백 GB까지 안정 |
| 백업 | 파일 복사 | pg_dump, 스트리밍 복제 |
| 적합한 규모 | 개인, 소규모 | 팀, 프로덕션 |
# PostgreSQL 연결
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
Queue Mode: 대규모 실행 관리
기본적으로 n8n은 단일 프로세스에서 모든 워크플로우를 순차 실행한다. 동시에 많은 워크플로우가 트리거되면 병목이 생긴다.
Queue Mode란?
Bull + Redis를 활용하여 워크플로우 실행을 큐에 넣고, 여러 Worker가 분산 처리하는 방식.
┌──────────┐
│ Redis │ (작업 큐)
│ (Bull) │
└────┬─────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Worker 1 │ │ Worker 2 │ │ Worker 3 │
└──────────┘ └──────────┘ └──────────┘
설정
services:
n8n:
environment:
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_DB=0
n8n-worker:
image: n8nio/n8n:latest
command: n8n worker
environment:
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
deploy:
replicas: 3 # Worker 3개로 병렬 처리
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
워크플로우 레벨 최적화
불필요한 데이터 제거
노드 사이에 Edit Fields(Keep Only Set Fields: ON)를 넣어 불필요한 필드를 제거하면 메모리를 절약할 수 있다.
[HTTP: 대용량 API 응답]
→ [Edit Fields: 필요한 3개 필드만] ← 이것이 핵심
→ [다음 처리]
Split In Batches + Wait
API Rate Limit 대응:
[10,000개 아이템]
→ [Split In Batches: 100개씩]
→ [HTTP Request: API 호출]
→ [Wait: 1초]
→ [Loop]
병렬 vs 순차 판단
| 상황 | 권장 |
|---|---|
| API에 Rate Limit이 있음 | 순차 (Split In Batches) |
| 독립적인 여러 API 호출 | 병렬 (분기 + Merge) |
| 대용량 DB 쿼리 | 배치 쿼리 (LIMIT + OFFSET) |
모니터링: Prometheus + Grafana
n8n은 Prometheus 메트릭을 기본 제공한다.
environment:
- N8N_METRICS=true
- N8N_METRICS_PREFIX=n8n_
주요 메트릭
| 메트릭 | 설명 |
|---|---|
n8n_workflow_execution_total | 총 실행 횟수 |
n8n_workflow_execution_duration | 실행 소요 시간 |
n8n_workflow_execution_errors_total | 에러 횟수 |
n8n_queue_length | 큐 대기 작업 수 (Queue Mode) |
Grafana 대시보드
Prometheus + Grafana를 연결하면 실시간 모니터링 대시보드를 구축할 수 있다:
- 시간별 실행 횟수 그래프
- 에러율 추이
- 평균 실행 시간
- 큐 대기 길이 (Queue Mode)
성능 최적화 체크리스트
| 항목 | 체크 |
|---|---|
| Binary Data → filesystem 모드 전환 | □ |
| SQLite → PostgreSQL 마이그레이션 | □ |
| 실행 데이터 자동 정리(Prune) 설정 | □ |
| 불필요한 필드 제거 (Keep Only Set Fields) | □ |
| API 호출 → Split In Batches + Wait | □ |
| Prometheus 메트릭 활성화 | □ |
| Docker 메모리 제한 설정 | □ |
| 대규모 워크플로우 → Queue Mode 고려 | □ |
📝 정리
- [x] 메모리: Binary Data filesystem 모드, Docker 메모리 제한
- [x] DB: SQLite → PostgreSQL 마이그레이션, 실행 데이터 Pruning
- [x] Queue Mode: Redis + Bull로 분산 Worker 실행
- [x] 워크플로우 최적화: 불필요 데이터 제거, 배치 처리, 병렬 vs 순차 판단
- [x] 모니터링: Prometheus 메트릭 + Grafana 대시보드
다음 편 예고
29편: n8n 프로젝트 실전 — 콘텐츠 자동 배포 파이프라인
지금까지 배운 모든 것을 총동원하는 실전 프로젝트. RSS 수집 → AI 요약 → 블로그 포스트 생성 → SNS 자동 배포.