🤖 [STEP 6] 시스템 자동화 및 AI/크립토 자동화 시스템

13. [Self-Healing] 장애 시 자동 복구되는 시스템 설계: "무너진 인프라를 스스로 치유하는 고차원 방어 시스템"

Bobaero Booktech-Lab 2026. 6. 27. 12:05

안녕하세요! 보배로의 북테크랩입니다.

지난 시간, 우리는 리눅스 OS 레벨에서 봇의 맥박을 감시하고, 좀비 상태나 다운된 프로세스에 스스로 심폐소생술을 실시하는 [Heartbeat(하트비트)] 시스템을 구축했습니다. 덕분에 프로세스가 무너져도 5초 만에 강제 부팅되는 질긴 생명력을 얻게 되었죠.

하지만 프로세스가 다시 켜진다고 해서 모든 문제가 해결될까요? 만약 클라우드 인프라의 일시적 네트워크 단선으로 인해 도커 컨테이너 간의 격벽이 깨졌거나, 거래소와의 웹소켓 소켓 세션 자체가 망가진 상태라면 프로세스만 켜진 채 여전히 아무런 데이터도 받지 못하는 '불구' 상태가 될 수 있습니다.

진정한 불사의 시스템은 단순히 프로세스를 재시작하는 것을 넘어, 망가진 네트워크 연결을 추적하여 재연결하고, 컨테이너 환경 자체를 물리적으로 재빌드하는 자가 치유 능력이 있어야 합니다. 오늘은 장애를 스스로 인지하고 인프라 전체를 원격 복구하는 Self-Healing(자가 치유) 아키텍처를 설계해 보겠습니다.

1. 자가 치유(Self-Healing)의 핵심 메커니즘 : "격리벽과 재연결 뼈대"

자동매매 인프라에서 자가 치유는 크게 두 가지 레이어로 작동해야 합니다.

  • 애플리케이션 레이어 (Exponential Backoff 재연결): 거래소 API 서버가 터졌거나 인터넷이 불안정할 때, 무작정 1초마다 재연결을 시도하면 거래소 방화벽에 DDoS 공격으로 찍혀 IP 차단을 당합니다(10강 사례). 재연결 시도 간격을 1초, 2초, 4초, 8초처럼 기하급수적으로 늘려가며 서버와 나 자신을 보호하는 지혜가 필요합니다.
  • 인프라 레이어 (Docker Container Healthcheck): 프로세스가 떠 있어도 내부 네트워크 세션이 완전히 꼬여버렸을 때, 도커(Docker) 엔진이 이를 감지하고 컨테이너 자체를 완전히 소멸시킨 뒤 깨끗한 상태로 재창조(Restart)하는 격벽 방어입니다.

2. [실습] Exponential Backoff 재연결 및 Docker 헬스체크 구현

실전 투자 환경에서 강력한 복구력을 발휘하는 자가 치유 로직과 인프라 설정 코드를 구현해 보겠습니다.

1단계: 파이썬 기하급수적 백오프 재연결 코드 (self_healing_conn.py)

Python
 
import asyncio
import random
import logging

async def connect_to_exchange_with_retry():
    """
    장애 발생 시 기하급수적으로 대기 시간을 늘려가며(Exponential Backoff)
    거래소 웹소켓 세션을 자가 치유하는 핵심 함수입니다.
    """
    base_delay = 1.0  # 초기 대기 시간 (1초)
    max_delay = 60.0  # 최대 대기 한도 (60초)
    max_retries = 5
    
    for attempt in range(1, max_retries + 1):
        try:
            logging.info(f"[Self-Healing] 거래소 보안 세션 연결 시도 중... (시도 {attempt}/{max_retries})")
            
            # 💡 의도적 연결 실패 시뮬레이션 (네트워크 단선 상황)
            if attempt < 3:
                raise ConnectionError("거래소 방화벽 응답 없음 (Timeout)")
                
            # 3번째 시도에서 연결 성공 가정
            logging.info("[Success] 거래소 세션 자가 치유 완료! 정상 트레이딩 전선 복귀.")
            return True
            
        except ConnectionError as ce:
            if attempt == max_retries:
                logging.error(f"[Fatal] {max_retries}회 재연결 실패. 인프라 레이어 복구로 이관합니다.")
                raise ce
                
            # 💡 기하급수적 대기 시간 계산 + 지터(Jitter) 추가
            # 통신학에서 지터는 여러 봇이 동시에 재연결을 시도해 서버를 터뜨리는 병목을 방지합니다.
            delay = min(base_delay * (2 ** (attempt - 1)) + random.uniform(0, 0.5), max_delay)
            logging.warning(f"[Warning] 연결 실패: {ce}. {delay:.2f}초 후 재시도합니다.")
            await asyncio.sleep(delay)

async def main():
    logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
    await connect_to_exchange_with_retry()

if __name__ == "__main__":
    asyncio.run(main())

2단계: Docker 헬스체크 및 자동 복구 환경 (docker-compose.yml)

파이썬 코드가 완전히 먹통이 되었을 때를 대비해, 도커 인프라 레벨에서 봇을 감시하고 컨테이너를 자동 재시작하도록 격벽 설정을 세웁니다.

YAML
 
version: '3.8'

services:
  bobaero_trading_bot:
    image: python:3.11-slim
    container_name: bobaero-trading-engine
    volumes:
      - .:/app
    working_dir: /app
    environment:
      - VAULT_ADDR=http://vault:8200
    command: python main_bot.py
    
    # 💡 도커 엔진이 봇의 생존을 직접 물리적으로 테스트합니다.
    healthcheck:
      # 8000번 포트(11강 Prometheus 포트)가 살아있는지 curl로 팅겨봅니다.
      test: ["CMD", "curl", "-f", "http://localhost:8000/metrics", "||", "exit", "1"]
      interval: 30s  # 30초마다 검사
      timeout: 10s   # 응답 대기는 최대 10s
      retries: 3     # 3회 연속 실패 시 'Unhealthy(위험)' 상태로 규정
      start_period: 15s # 봇이 처음 켜질 때 초기화 유예 시간 15초 부여

    # 💡 Unhealthy 상태가 되거나 프로세스가 다운되면 컨테이너를 즉시 재빌드하여 자가 치유합니다.
    restart: always

📖 실제 장애 사고 사례: "타임아웃 대홍수와 거래소 영구 블랙리스트"

과거 한 트레이더가 아주 사소한 에러 예외 처리를 누락한 채 봇을 가동했습니다. 어느 날 새벽 4시, 거래소 서버의 정기 점검으로 인해 약 5분간 API 통신이 일시적으로 끊겼습니다.

그의 봇은 세션 유실을 인지하자마자 자가 치유 전략(Backoff) 없이, while True: 루프 속에서 1초에 100번씩 무자비하게 재연결 요청을 쏘아 보냈습니다. 점검이 끝나고 방화벽이 켜지자마자, 거래소 보안 시스템은 이 봇을 '악의적인 서비스 거부 공격(DoS)'으로 판단했습니다. 결과는 무시무시했습니다. 단순한 24시간 차단이 아니라, 해당 트레이더의 API Key와 AWS 서버 IP를 영구 블랙리스트(Permanent Ban)에 등록해 버렸습니다.

포지션을 잡고 있던 자산들은 묶여버렸고, 수동으로 웹 브라우저에 접속해 허겁지겁 청산하기 전까지 엄청난 슬리피지와 자산 손실을 감당해야 했습니다. 제어되지 않는 무식한 재연결은 자가 치유가 아니라, 시스템을 파괴하는 흉기입니다.

🛡️ 자가 치유(Self-Healing) 시스템 운영 체크리스트

  • [ ] 지터(Jitter) 포함 백오프: 재연결 대기 시간을 계산할 때 거래소 서버의 동시 병목을 막기 위해 랜덤한 난수(Jitter)를 반드시 더해주었는가?
  • [ ] 도커 헬스체크 연동: 11강에서 개방한 Prometheus 메트릭 포트(8000) 등을 활용해 도커 엔진이 실제 프로세스의 생존을 교차 검증하고 있는가?
  • [ ] 임계치 초과 시 알림: 자가 치유 시도가 최대치(예: 5회)를 초과해 실패했을 경우, 인프라가 다운되기 전 즉시 외부 채널로 SOS 알림을 보내도록 설계했는가?
  • [ ] Fail-Safe 자산 동결: 컨테이너가 강제로 재시작되기 직전, 현재 체결 대기 중인 모든 미체결 주문을 취소하고 자산을 안전하게 보존하는 파괴 명령(Graceful Shutdown)이 작동하는가?

📝 보배로의 통찰: "최고의 시스템은 상처 입지 않는 것이 아니라, 상처를 스스로 치유하는 것이다"

우리는 흔히 완벽한 코드, 무결한 인프라를 꿈꿉니다. 그러나 복잡계인 클라우드 네트워크와 글로벌 가상자산 시장에서 '절대 깨지지 않는 연결'이란 존재하지 않습니다. 진정한 공학적 가치는 시스템이 상처를 입고 쓰러지는 순간, Exponential Backoff로 거래소를 달래고, Docker 헬스체크로 스스로의 껍질을 깨고 다시 태어나는 자가 치유 메커니즘을 갖추었을 때 실현됩니다. 이 방어벽을 믿고 봇에게 과감히 시장을 맡기십시오.

인프라가 스스로 상처를 치료하고 불사의 생명력을 얻었으니, 이제 이 모든 위대한 전투 상황을 우리 주머니 속에서 실시간으로 보고받고 제어할 차례입니다.

다음 시간에는 서버에 복잡하게 접속할 필요 없이 스마트폰 하나로 봇에게 명령을 내리고 보고를 받는 관제 허브, [14. 텔레그램 봇 연동] 내 주머니 속의 실시간 시스템 관제실 구축에 대해 알아보겠습니다.

보배로의 북테크랩(Booktech-lab) 공학적으로 투자하고, 데이터로 증명하며, 시스템으로 승리합니다.