Make에서 n8n 셀프호스팅으로 옮기다 OOMKilled와 SQLITE_BUSY로 사흘 날린 기록
정유나
@yuna_ai
회사에서 Make(구 Integromat)로 돌리던 자동화를 n8n 셀프호스팅으로 옮겼다. 이유는 단순하다. operations 한도를 자꾸 넘겨 요금제를 올려야 하는 상황이 반복됐는데, 정작 우리 시나리오는 무겁지 않고 그냥 자주 돌 뿐이었다. 셀프호스팅하면 서버비만 들 텐데 싶어 옮겼다. 옮긴 것 자체는 후회 안 하는데, 첫 사흘은 삽질로 날렸다. 그 사흘을 정리해둔다.
만들려던 건 별게 아니었다. Airtable에 새 레코드가 들어오면 영업 Slack 채널에 알림을 쏘는 봇이다.
1. exit code 137 — OOMKilled
사내에 굴러다니던 t3.small(RAM 2GB) EC2에 문서 그대로 docker로 띄웠다.
docker run -it --rm --name n8n -p 5678:5678 n8nio/n8n
데모는 멀쩡했다. 그런데 이틀쯤 지나니 컨테이너가 자꾸 죽어 있었다. docker logs n8n에는 스택트레이스도 없이 이 한 줄만 남았다.
n8n exited with code 137
137 = 128 + 9, 즉 SIGKILL이고 보통 OOM이면 이렇게 나온다. 호스트에서 dmesg를 보니 확정이었다.
Out of memory: Killed process 2117 (node)
Memory cgroup out of memory
n8n은 node로 워크플로우를 돌리며 실행 데이터를 메모리에 들고 있는데, 우리 워크플로우 중 Airtable에서 한 번에 레코드 수백 개를 fetch하는 노드가 그걸 통째로 메모리에 올렸다. docker stats로 옆에서 보면 그 노드가 도는 순간 메모리가 튀고, 끝나도 잘 안 내려왔다. 특히 페이로드가 큰 바이너리를 다룰 때 심했다.
2. execution 데이터 무한 적재
메모리를 추적하다 보니 database.sqlite 파일이 계속 커지고 있었다. n8n은 기본적으로 execution 기록을 안 지운다. 메모리와 직접 인과인지는 확신 못 하지만, 안 쌓이게 하는 게 맞다 싶어 prune을 켰다.
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
(168시간 = 1주일) 죽는 빈도는 줄었지만 근본 해결은 아니었다. 결국 t3.medium(RAM 4GB)으로 올리니 그제서야 fetch 노드를 삼키고 안 죽었다. 솔직히 두 번째가 훨씬 컸다. 메모리 부족은 메모리로 푸는 게 맞았다.
3. SQLITE_BUSY — 조용히 누락되던 알림
OOM을 잡고 나니 더 골치 아픈 게 남았다. 알림이 가끔, 진짜 가끔 안 왔다. 컨테이너는 멀쩡히 살아 있는데. 로그를 한참 뒤지다 찾았다.
QueryFailedError: SQLITE_BUSY: database is locked
워크플로우 몇 개가 동시에 겹쳐 돌면 SQLite에 락이 걸리고, 그 실행이 조용히 실패했다. 에러는 로그에만 찍히고 워크플로우 상태는 그냥 넘어가니, 빠진 줄도 몰랐다. 컨테이너가 죽으면 차라리 알지, 살아 있으면서 한두 건씩 조용히 빠지는 게 제일 무섭다. 영업팀이 "그 문의 알림 안 왔는데요?" 하기 전까진 몰랐다.
답은 Postgres였다. 같은 호스트에 postgres 컨테이너를 하나 더 띄우고 붙였다.
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_DATABASE=n8n
바꾸고 나서 database is locked는 한 번도 안 떴다. 셀프호스팅 문서에 production은 Postgres 쓰라고 적혀 있는데, 데모가 잘 돈다고 SQLite 기본값으로 넘긴 게 화근이었다.
한 달 굴려보고
지금은 한 달 넘게 안정적이다. Make의 월 ops 게이지를 신경 쓰던 것에 비하면 마음은 편하다. 다만 공짜는 아니다. OOM이 나면 새벽에 인스턴스를 만져야 하고, DB 백업도 직접 챙겨야 한다. Make는 그 운영 부담을 돈으로 산 것이었다는 걸 옮기고 나서 알았다. 팀에 docker·노드를 만져본 사람이 있으면 셀프호스팅이 충분히 할 만하고, 아무도 없으면 클라우드 결제가 정신건강에 낫다. 처음부터 production 기준(증설된 인스턴스 + Postgres + execution prune)으로 깔았으면 사흘을 안 날렸을 것이다.