[AI] 08_ADR_ 041‐045 - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki

ADR 041-045: 인프라 확장 및 하이브리드 스케일링

Architecture Decision Records (ADR) 041-045
인프라 확장성 및 하이브리드 스케일링 전략


📚 목차


ADR-041: 하이브리드 스케일링 전략 (RunPod + Lambda)

📋 메타데이터

항목 내용
상태 ✅ 승인됨 (Accepted)
작성일 2026-01-14
결정자 AI/인프라팀
관련 기능 GPU 서버, 서버리스, 로드 밸런싱, 오토스케일링

🎯 컨텍스트 (Context)

AI 서비스의 트래픽 패턴을 분석한 결과, 평시와 피크 타임의 부하 차이가 명확합니다.

트래픽 패턴:

  • 평시 부하: 70% (예측 가능, 안정적)
  • 피크 부하: +30% (점심시간, 저녁시간, 주말)

문제점:

  • RunPod 단독 사용 시 피크 타임 대비 과도한 리소스 할당 필요
  • 평시에는 30% 리소스 유휴 상태 → 비용 낭비
  • 오토스케일링만으로는 GPU 서버의 빠른 확장 어려움

요구사항:

  • 평시 부하는 안정적으로 처리 (RunPod)
  • 피크 부하는 유연하게 대응 (서버리스)
  • 비용 최적화 (유휴 리소스 최소화)
  • 안정성 확보 (이중화)

🔍 선택지 분석 (Options)

Option 1: RunPod 단독 (피크 대비 스펙)

┌─────────────────────────────────────────────────────────┐
│  RunPod 단독 (100% 처리)                                 │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [RunPod 서버]                                          │
│  ├─ GPU: RTX 4090                                       │
│  ├─ 스펙: 피크 타임 대비 (100%)                         │
│  ├─ 비용: $500/월                                       │
│  └─ 평시 유휴: 30% (낭비)                               │
│                                                         │
└─────────────────────────────────────────────────────────┘
장점 단점
단순한 구조 평시 30% 유휴 리소스
안정적 성능 높은 비용 ($500/월)
관리 용이 확장성 제한

Option 2: Lambda 단독 (서버리스)

┌─────────────────────────────────────────────────────────┐
│  Lambda 단독 (100% 처리)                                 │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [Lambda 함수]                                          │
│  ├─ 자동 스케일링                                       │
│  ├─ 사용량 기반 과금                                    │
│  ├─ 비용: $100/월 (예상)                                │
│  └─ Cold Start 이슈                                     │
│                                                         │
└─────────────────────────────────────────────────────────┘
장점 단점
사용량 기반 과금 Cold Start 지연 (1~3초)
무제한 확장 GPU 미지원
관리 부담 없음 실행 시간 제한 (15분)

Option 3: 하이브리드 (RunPod + Lambda) ⭐

┌─────────────────────────────────────────────────────────┐
│  하이브리드 스케일링                                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [사용자 요청]                                          │
│      ↓                                                  │
│  [API Gateway / ALB] ← 로드 밸런서                      │
│      ├─ 라우팅 규칙                                     │
│      ├─ 헬스 체크                                       │
│      └─ 트래픽 분산                                     │
│      ↓                                                  │
│  ┌──────────────────┬──────────────────┐               │
│  │                  │                  │               │
│  │  [RunPod 서버]   │  [Lambda 함수]   │               │
│  │  (베이스 라인)   │  (버스트)        │               │
│  │                  │                  │               │
│  │  평시 부하 70%   │  피크 부하 30%   │               │
│  │  ├─ GPU 서버     │  ├─ 서버리스     │               │
│  │  ├─ 항상 ON      │  ├─ 피크만 ON    │               │
│  │  └─ $350/월      │  └─ $30/월       │               │
│  │                  │                  │               │
│  └──────────────────┴──────────────────┘               │
│      ↓                      ↓                          │
│  [AI 모델 추론]                                         │
│                                                         │
│  총 비용: $380/월 (RunPod 단독 대비 24% 절감)           │
│                                                         │
└─────────────────────────────────────────────────────────┘
장점 단점
비용 최적화 (24% 절감) 구현 복잡도 증가
안정성 확보 (이중화) 두 시스템 관리 필요
유연한 확장 (무제한) 라우팅 로직 필요
유휴 리소스 최소화 모니터링 복잡

✅ 결정 (Decision)

Option 3: 하이브리드 스케일링 전략 채택

버전 구성 이유
V1~V2 RunPod 단독 MVP, 트래픽 패턴 파악
V3 RunPod + Lambda 비용 최적화, 안정성
V4 RunPod + Lambda + K8s 대규모 확장

📝 근거 (Rationale)

1. 트래픽 패턴 분석

실제 트래픽 데이터 (예상):

시간대별 요청 수:
00:00-06:00: 10 req/min (10%)
06:00-09:00: 50 req/min (50%)
09:00-12:00: 70 req/min (70%) ← 평시
12:00-14:00: 100 req/min (100%) ← 피크!
14:00-18:00: 70 req/min (70%)
18:00-21:00: 90 req/min (90%) ← 피크!
21:00-24:00: 40 req/min (40%)

평균: 70 req/min (평시)
피크: 100 req/min (점심, 저녁)

부하 분석:

  • 평시 (70%): RunPod로 안정적 처리
  • 피크 (+30%): Lambda로 버스트 처리

2. 비용 분석

RunPod 단독 (피크 대비):

RunPod 서버:
- GPU: RTX 4090
- 스펙: 100% 처리 가능
- 비용: $500/월
- 평시 유휴: 30% ($150/월 낭비)

총 비용: $500/월

하이브리드 (RunPod 70% + Lambda 30%):

RunPod 서버:
- GPU: RTX 4090
- 스펙: 70% 처리 (다운사이징)
- 비용: $350/월

Lambda 함수:
- 피크 타임만 활성화
- 30,000 requests/월
- 비용: $30/월

총 비용: $380/월
절감: $120/월 (24%)

3. 라우팅 전략

스마트 라우팅 로직:

# routing-logic.py
import boto3
from datetime import datetime

cloudwatch = boto3.client('cloudwatch')

def route_request(request):
    """스마트 라우팅 - RunPod vs Lambda"""
    
    # 1. RunPod 서버 상태 확인
    runpod_cpu = get_runpod_cpu_usage()
    runpod_healthy = check_runpod_health()
    
    # 2. 라우팅 결정
    if runpod_healthy and runpod_cpu < 70:
        # RunPod 여유 있음 → RunPod 사용
        return route_to_runpod(request)
    else:
        # RunPod 부하 높음 → Lambda 사용
        return route_to_lambda(request)

def get_runpod_cpu_usage():
    """RunPod CPU 사용률 조회"""
    response = cloudwatch.get_metric_statistics(
        Namespace='RunPod',
        MetricName='CPUUtilization',
        Dimensions=[{'Name': 'ServerID', 'Value': 'runpod-1'}],
        StartTime=datetime.now() - timedelta(minutes=5),
        EndTime=datetime.now(),
        Period=300,
        Statistics=['Average']
    )
    
    if response['Datapoints']:
        return response['Datapoints'][0]['Average']
    return 0

def check_runpod_health():
    """RunPod 헬스 체크"""
    try:
        response = requests.get('https://runpod-server.com/health', timeout=2)
        return response.status_code == 200
    except:
        return False

def route_to_runpod(request):
    """RunPod으로 라우팅"""
    return requests.post('https://runpod-server.com/api/inference', json=request)

def route_to_lambda(request):
    """Lambda로 라우팅"""
    lambda_client = boto3.client('lambda')
    response = lambda_client.invoke(
        FunctionName='ai-burst-handler',
        InvocationType='RequestResponse',
        Payload=json.dumps(request)
    )
    return json.loads(response['Payload'].read())

4. Lambda 함수 구현

# lambda_function.py
import json
from langchain_google_genai import ChatGoogleGenerativeAI

def lambda_handler(event, context):
    """Lambda 함수 - 피크 타임 버스트 처리"""
    
    try:
        # 요청 파싱
        body = json.loads(event['body']) if isinstance(event['body'], str) else event['body']
        prompt = body.get('prompt')
        model = body.get('model', 'gemini-3-flash')
        
        # LLM 호출
        llm = ChatGoogleGenerativeAI(model=model)
        response = llm.invoke(prompt)
        
        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json',
                'X-Source': 'lambda'  # 디버깅용
            },
            'body': json.dumps({
                'result': response.content,
                'source': 'lambda',
                'model': model
            })
        }
        
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({
                'error': str(e),
                'source': 'lambda'
            })
        }

5. API Gateway 설정

# api-gateway.yaml
Resources:
  ApiGateway:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: AI-Hybrid-Gateway
      ProtocolType: HTTP
      
  # RunPod 통합
  RunPodIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref ApiGateway
      IntegrationType: HTTP_PROXY
      IntegrationUri: https://runpod-server.com/api
      IntegrationMethod: POST
      PayloadFormatVersion: '1.0'
      
  # Lambda 통합
  LambdaIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref ApiGateway
      IntegrationType: AWS_PROXY
      IntegrationUri: !GetAtt LambdaFunction.Arn
      PayloadFormatVersion: '2.0'
      
  # 라우트 (스마트 라우팅)
  InferenceRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref ApiGateway
      RouteKey: 'POST /inference'
      Target: !Join
        - /
        - - integrations
          - !Ref SmartRoutingIntegration

🔧 구현 예시

1. CloudWatch Alarm 설정

# cloudwatch-alarm.yaml
Resources:
  RunPodHighCPUAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: RunPod-High-CPU-Alarm
      AlarmDescription: RunPod CPU 70% 초과 시 Lambda 활성화
      MetricName: CPUUtilization
      Namespace: RunPod
      Statistic: Average
      Period: 300  # 5분
      EvaluationPeriods: 2
      Threshold: 70
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Ref LambdaScaleUpTopic
        
  LambdaScaleUpTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: Lambda Scale Up Notification
      Subscription:
        - Endpoint: !GetAtt LambdaFunction.Arn
          Protocol: lambda

2. 모니터링 대시보드

# monitoring-dashboard.py
import boto3
from datetime import datetime, timedelta

cloudwatch = boto3.client('cloudwatch')

def create_dashboard():
    """CloudWatch 대시보드 생성"""
    
    dashboard_body = {
        "widgets": [
            {
                "type": "metric",
                "properties": {
                    "title": "RunPod CPU 사용률",
                    "metrics": [
                        ["RunPod", "CPUUtilization", {"stat": "Average"}]
                    ],
                    "period": 300,
                    "region": "us-east-1",
                    "yAxis": {"left": {"min": 0, "max": 100}}
                }
            },
            {
                "type": "metric",
                "properties": {
                    "title": "Lambda 실행 횟수",
                    "metrics": [
                        ["AWS/Lambda", "Invocations", {"stat": "Sum"}]
                    ],
                    "period": 300,
                    "region": "us-east-1"
                }
            },
            {
                "type": "metric",
                "properties": {
                    "title": "트래픽 분산 비율",
                    "metrics": [
                        ["Custom", "RunPodRequests", {"stat": "Sum", "label": "RunPod"}],
                        ["Custom", "LambdaRequests", {"stat": "Sum", "label": "Lambda"}]
                    ],
                    "period": 300,
                    "region": "us-east-1"
                }
            }
        ]
    }
    
    cloudwatch.put_dashboard(
        DashboardName='AI-Hybrid-Scaling',
        DashboardBody=json.dumps(dashboard_body)
    )

📊 비교표

항목 RunPod 단독 Lambda 단독 하이브리드
월 비용 $500 $100 $380
평시 성능 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
피크 성능 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
안정성 ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
확장성 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
관리 복잡도 🔴 낮음 🔴🔴 중간 🔴🔴🔴 높음
V3 적합성 ⚠️ 추천

🎯 최종 추천

V1~V2 (MVP)

RunPod 단독
- 트래픽 패턴 파악
- 단순한 구조
- 비용: $500/월

V3 (하이브리드)

RunPod (70%) + Lambda (30%)
- 비용 최적화: $380/월
- 안정성 확보 (이중화)
- 유연한 확장

V4 (대규모)

RunPod + Lambda + K8s
- 무제한 확장
- 엔터프라이즈급 안정성
- 비용: $1,000+/월

💡 핵심 정리

하이브리드 스케일링 전략:

  1. RunPod (베이스 라인): 평시 70% 부하 처리

    • GPU 서버 (항상 ON)
    • 안정적 성능
    • $350/월
  2. Lambda (버스트): 피크 30% 부하 처리

    • 서버리스 (피크만 ON)
    • 자동 스케일링
    • $30/월
  3. 로드 밸런서: 스마트 라우팅

    • RunPod CPU < 70% → RunPod
    • RunPod CPU ≥ 70% → Lambda

이점:

  • ✅ 비용 절감: 24% ($120/월)
  • ✅ 안정성 향상: 이중화
  • ✅ 유연한 확장: 무제한
  • ✅ 유휴 리소스 최소화

📅 이력

날짜 변경 내용
2026-01-14 초기 결정 (하이브리드 스케일링 전략)

ADR-042: (예정)


ADR-043: (예정)


ADR-044: (예정)


ADR-045: (예정)


🎊 결론

V3 하이브리드 스케일링 전략 완성!

구성 요소 역할 비용
RunPod 베이스 라인 (70%) $350/월
Lambda 버스트 (30%) $30/월
API Gateway 로드 밸런싱 $10/월
CloudWatch 모니터링 $5/월
총 비용 - $395/월

절감 효과: RunPod 단독 대비 21% 절감 ($500 → $395) ✅

이제 비용 효율적이고 안정적인 인프라가 완성되었습니다! 🎉