별책부록 17편
별책부록 17편
다중봇 운영 (3개 이상)
8GB Cloud VPS 10 한 대로 12개 봇을 안정적으로 운영하는 방법입니다
📑 이 챕터에서 다룰 내용

봇 1개는 누구나 운영할 수 있습니다. 그러나 도메인이 늘어나면 (TSV·AlbaFlow·viewLab·줍줍...) 봇이 4·8·12개가 됩니다. 8GB RAM Cloud VPS 10에서 12개 봇을 안정적으로 운영하려면 체계적인 접근이 필요해요.

📘 이 편에서 다루는 내용
  • pm2 ecosystem.config.js 심화 설정
  • 자원 분배·메모리 한도 설정
  • 봇 간 통신 (Redis Pub/Sub)
  • 부하 분산 (Cloudflare Worker로 일부 분리)
  • 모니터링 종합 (한 대시보드에서 모든 봇 관리)
17-1 pm2 ecosystem.config.js 심화 🔗

기본 설정 (단순 버전)

💻 ecosystem.config.js — 기본형
module.exports = {
  apps: [
    { name: "tsv-bot", script: "tsv/main.py", interpreter: "python3" },
    { name: "albaflow-bot", script: "albaflow/main.py", interpreter: "python3" },
  ]
};

심화 설정 (12개 봇)

💻 ecosystem.config.js — 12개 봇 심화형
module.exports = {
  apps: [
    // === TSV 4개 봇 ===
    {
      name: "tsv-monitoring",
      script: "tsv/monitoring/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      env: {
        DATABASE_URL: process.env.DATABASE_URL,
        ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
        DISCORD_TOKEN: process.env.TSV_DISCORD_TOKEN,
        LOG_LEVEL: "info",
      },
      max_memory_restart: "300M",
      autorestart: true,
      restart_delay: 5000,
      max_restarts: 5,
      min_uptime: "30s",
      log_date_format: "YYYY-MM-DD HH:mm:ss",
      error_file: "/var/log/pm2/tsv-monitoring-error.log",
      out_file: "/var/log/pm2/tsv-monitoring-out.log",
      merge_logs: true,
    },
    {
      name: "tsv-b2b",
      script: "tsv/b2b/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      env: { /* ... */ },
      max_memory_restart: "200M",
    },
    {
      name: "tsv-position-c",
      script: "tsv/position_c/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      cron_restart: "0 0 * * *",  // 매일 자정 재시작
      max_memory_restart: "200M",
    },
    {
      name: "tsv-faq",
      script: "tsv/faq/main.js",
      env: { /* ... */ },
      max_memory_restart: "300M",
    },

    // === AlbaFlow 4개 봇 ===
    {
      name: "albaflow-owner",
      script: "albaflow/owner/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      env: { /* ... */ },
      max_memory_restart: "300M",
    },
    {
      name: "albaflow-alba",
      script: "albaflow/alba/main.js",
      env: { /* ... */ },
      max_memory_restart: "300M",
    },
    {
      name: "albaflow-labor-law",
      script: "albaflow/labor_law/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      cron_restart: "0 0 * * *",
      max_memory_restart: "200M",
    },
    {
      name: "albaflow-store",
      script: "albaflow/store/main.py",
      interpreter: "/home/ubuntu/.venv/bin/python3",
      cron_restart: "0 9 * * *",  // 매일 09:00
      max_memory_restart: "200M",
    },

    // === viewLab 4개 봇 ===
    { name: "viewlab-dealer",   script: "viewlab/dealer/main.py",   interpreter: "python3", max_memory_restart: "300M" },
    { name: "viewlab-content",  script: "viewlab/content/main.py",  interpreter: "python3", max_memory_restart: "200M" },
    { name: "viewlab-customer", script: "viewlab/customer/main.js",                         max_memory_restart: "300M" },
    { name: "viewlab-store",    script: "viewlab/store/main.py",    interpreter: "python3", max_memory_restart: "200M" },
  ]
};
💡 핵심 설정 항목 설명
  • max_memory_restart — 메모리가 이 한도를 초과하면 자동 재시작. 메모리 누수를 막는 가장 중요한 설정이에요.
  • min_uptime: "30s" — 30초 미만에 죽으면 비정상 종료로 간주. 무한 재시작 루프를 방지합니다.
  • max_restarts: 5 — 5번 재시작 실패 시 pm2가 포기하고 멈춥니다. Sentry 알림으로 즉시 파악하세요.
  • cron_restart — 정해진 시간에 정기 재시작. 메모리 누수가 있는 봇에 유용합니다.

자원 계획 — 12개 봇 기준

항목설정 기준비고
12개 봇 × 평균 250MB3GBmax_memory_restart로 제어
8GB RAM 대비 봇 사용량37%안전한 수준
시스템 + PostgreSQL + 기타~2GB예상치
여유 메모리~3GB충분한 여유
17-2 자원 분배 전략 🔗

메모리 분배 계획 (8GB RAM 기준)

구성 요소메모리 할당
시스템 + Linux1GB
PostgreSQL1GB
Redis200MB
nginx50MB
봇 12개 합계3GB (평균 250MB × 12)
여유2.75GB

봇별 메모리 패턴

봇 유형평균 메모리Anthropic 호출 시
Python 봇200~300MB+100MB (일시적)
Node.js 봇250~400MB+100MB (일시적)
대용량 데이터 처리 시+200MB (일시적) — max_memory_restart로 관리

CPU 고려사항 (4 코어)

📘 이벤트 기반 봇의 CPU 특성

12개 봇이 동시에 실행되지만, 봇은 대부분 이벤트 기반으로 동작해요. 메시지가 없을 때는 거의 idle 상태입니다.

  • 동시 CPU 집중 작업: 최대 4개 (코어 수 기준)
  • 주의: 한 봇이 무한 루프에 빠지면 CPU 100% → 다른 봇 영향
  • 대응: max_memory_restart와 함께 CPU 모니터링 필수

디스크 분배 계획 (100GB 기준)

항목예상 용량
시스템5GB
봇 코드1GB
DB (PostgreSQL)10~50GB (사용자 규모에 따라 다름)
로그5~10GB
여유 공간35~80GB
⚠️ 디스크 관리 주의사항
  • 로그가 무한정 커질 수 있어요 → logrotate 설정 필수
  • DB 행 수가 늘면 인덱스 성능 저하 → 정기 vacuum
  • /var/log/pm2/ 폴더 크기를 주기적으로 확인하세요
17-3 봇 간 통신 (Redis Pub/Sub) 🔗

12개 봇이 서로 정보를 공유해야 할 때가 있습니다. 예를 들어 TSV 봇이 새 이벤트를 감지하면 운영자 알림 봇에 전달하는 구조입니다. 1인 운영자가 여러 도메인을 통합 관리할 때 유용해요.

Redis Pub/Sub 구현 예시

💻 bots/shared/pubsub.py
import redis.asyncio as redis
import json

class BotPubSub:
    def __init__(self):
        self.redis = redis.Redis(host='localhost', port=6379)

    async def publish(self, channel: str, message: dict):
        """이벤트 발행"""
        await self.redis.publish(channel, json.dumps(message))

    async def subscribe(self, channel: str, handler):
        """이벤트 구독"""
        pubsub = self.redis.pubsub()
        await pubsub.subscribe(channel)
        async for message in pubsub.listen():
            if message['type'] == 'message':
                data = json.loads(message['data'])
                await handler(data)

# --- 사용 예시 ---

# TSV 모니터링 봇: 이벤트 발행
await pubsub.publish("system_alert", {
    "type": "high_error_rate",
    "domain": "tsv",
    "severity": "warning"
})

# 운영자 알림 봇: 이벤트 구독 (모든 도메인 종합)
async def handle_alert(data):
    if data["severity"] == "warning":
        await send_discord_alert(data)

await pubsub.subscribe("system_alert", handle_alert)

Redis 활용 범위

용도구체적 예시
봇 → 봇 알림TSV 모니터링 → 운영자 알림: "일별 리포트 준비 완료"
응답 없음 감지AlbaFlow 사장님 봇 → 운영자: "응답 지연 감지"
Heartbeat모든 봇 → 모니터링 봇: 정기 생존 신호
메시지 큐BullMQ·Celery 백엔드로 활용
캐시Anthropic 응답 결과 캐싱
세션사용자 대화 컨텍스트 저장
Rate limit봇별 API 호출 횟수 제한
17-4 부하 분산 — Cloudflare Worker 분리 🔗

VPS 자원에 한계가 있을 때 가벼운 작업은 Cloudflare Worker로 분리하면 VPS 부하를 크게 줄일 수 있어요.

Worker vs VPS — 작업 분배 기준

Cloudflare Worker 적합VPS 적합
✓ FAQ 응답 (단순·캐시 가능)✓ 장시간 처리 (Anthropic stream)
✓ Webhook 수신 (Discord·Telegram·Stripe)✓ 큰 메모리 작업
✓ HTTP API 처리✓ Persistent 연결 (Discord 봇 WebSocket)
✓ Rate limit·인증 처리✓ DB 읽기·쓰기
✓ 정적 데이터 처리✓ cron 작업 (시간 정확도 필요)

분리 전후 비교

구분VPS 메모리 사용Worker 비용
분리 전 (모두 VPS)1.7GB / 8GB
분리 후 (Worker 활용)1.0GB / 8GB (40% 절약)100K req/일 무료
💡 Cloudflare Worker 무료 플랜 한도

하루 100,000 요청까지 무료입니다. FAQ 봇·Webhook 처리 정도는 무료 한도 안에서 충분히 운영 가능해요.

초과 시: $5/월 (1,000만 요청까지) — 여전히 매우 저렴합니다.

17-5 모니터링 종합 — 한 대시보드에서 🔗

옵션 A — 단순 구성 (권장: 처음 12개 봇)

도구역할비용
pm2 monitCLI에서 모든 봇 상태·메모리·CPU 확인무료
Sentry에러 수집·알림무료 (소규모)
Anthropic ConsoleAPI 비용·사용량무료
Cloudflare DashboardWorker 요청 수·에러율무료

옵션 B — 고급 구성 (봇 50개+ 시 검토)

도구역할메모리
Grafana차트·대시보드·알림~250MB
Prometheus메트릭 수집~200MB
합계 추가 비용8GB 중 총 2.2GB 사용 (27%)~500MB
📘 처음에는 단순하게 시작하세요

봇 12개 수준에서는 pm2 monit + Sentry 조합으로 충분합니다. Grafana·Prometheus는 봇이 50개를 넘어서 복잡해질 때 도입을 검토하세요.

지금 당장 복잡한 모니터링 시스템을 구축하는 것보다 봇 품질을 높이는 편이 훨씬 효과적이에요.

17-6 함정 4가지 회피 🔗
⚠️ 함정 1 — 모든 봇이 같은 시간에 작동

문제: 12개 봇이 매일 09:00에 동시 시작 → CPU·API 호출 폭발 → Anthropic rate limit 초과

해결: cron_restart로 시작 시간을 5분씩 분산하세요.

💻 cron_restart 시간 분산 예시
cron_restart: "0 9 * * *",   // 봇 1 — 09:00
cron_restart: "5 9 * * *",   // 봇 2 — 09:05
cron_restart: "10 9 * * *",  // 봇 3 — 09:10
cron_restart: "15 9 * * *",  // 봇 4 — 09:15
// ... 5분 간격으로 배치
⚠️ 함정 2 — 한 봇이 다른 봇 자원을 독식

문제: TSV 봇 메모리 누수 → 4GB 점유 → 다른 봇 메모리 부족 → 연쇄 종료

해결: 모든 봇에 max_memory_restart 필수 설정. 봇당 300~500MB 한도를 권장합니다.

⚠️ 함정 3 — API 키 한 개를 모든 봇이 공유

문제: 한 API 키 공유 → 한 봇의 코드 오류 → 모든 봇의 API 차단

해결: 도메인별로 별도 API 키를 사용하세요 (TSV 키·AlbaFlow 키·viewLab 키...). 한 봇에 문제가 생겨도 다른 봇에 영향이 없습니다.

⚠️ 함정 4 — DB 연결 수 폭발

문제: 12개 봇 × 각 봇 10개 connection = 120개. PostgreSQL 기본 max_connections는 100이에요.

해결 (3가지 중 택1):

  • PgBouncer 도입 — connection pool 미들웨어. 가장 권장하는 방법
  • PostgreSQL max_connections 증가 (200~500) — 메모리 사용량 증가 감안
  • 봇당 connection 수 제한 (1~3개) — 코드 레벨에서 pool 크기 설정
17-7 운영 흐름 — Junho 기준 🔗

매일 점검 (4분)

시간작업
09:00pm2 status — 12개 봇 상태 일괄 확인
09:01free -h — 메모리·CPU 현황
09:02Sentry 에러 확인
09:03Anthropic 비용 확인
09:04완료 ✅

새 봇 추가 절차 (월 1회 정도)

1
자원 검토

현재 자원 사용량을 확인합니다. 새 봇이 사용할 예상 메모리를 계산하고 여유 공간이 충분한지 확인하세요.

2
코드 작성 + 테스트

로컬에서 먼저 실행해보고 단위 테스트 + 통합 테스트를 모두 통과시킵니다.

3
ecosystem.config.js 추가

새 봇 항목을 추가합니다. max_memory_restart와 환경 변수 설정을 반드시 포함하세요.

4
배포

git push → GitHub Actions 자동 배포 (별책부록 9편) → pm2 reload ecosystem.config.js

5
24시간 모니터링

배포 후 하루 동안 메모리·에러를 면밀히 관찰합니다. 자원이 안정적으로 유지되면 완료입니다.

📌 17편 정리

  • 8GB Cloud VPS 10 한 대로 12개 봇을 안정적으로 운영할 수 있습니다 — 메모리 사용량은 37%에 불과해요.
  • pm2 ecosystem.config.js 심화: max_memory_restart + min_uptime + max_restarts 3종 세트는 필수입니다.
  • 자원 분배: 봇당 300~500MB 한도, logrotate, 정기 DB vacuum으로 장기 안정성을 확보하세요.
  • Redis Pub/Sub: 봇 간 통신·캐시·세션·Rate limit을 한 곳에서 처리할 수 있습니다.
  • Cloudflare Worker 분리: 가벼운 작업을 분리하면 VPS 메모리를 40% 절약할 수 있어요.
  • 4가지 함정 회피: 시작 시간 분산 / 메모리 한도 / 도메인별 API 키 / PgBouncer로 DB 연결 관리.
📘
별책부록 도우미
질문하기 OK
안녕하세요! 다중봇 운영에 대해 무엇이든 물어보세요. 본문에서 찾아 답변해드릴게요. 👇