콘텐츠로 이동

오류 처리 가이드

이 가이드는 Continuum Router의 오류 처리 메커니즘, 상태 코드, 재시도 전략 및 문제 해결을 다룹니다.

목차

오류 범주

클라이언트 오류 (4xx)

수정 없이는 재시도하면 안 되는 잘못된 클라이언트 요청으로 인한 오류입니다.

범주 설명 예제
유효성 검사 오류 잘못된 요청 형식 또는 매개변수 필수 필드 누락, 잘못된 JSON
인증 오류 인증 또는 권한 부여 실패 잘못된 API 키, 만료된 토큰
리소스 오류 요청한 리소스를 찾을 수 없음 사용할 수 없는 모델, 엔드포인트를 찾을 수 없음
속도 제한 오류 너무 많은 요청 쿼터 초과, 속도 제한 도달

서버 오류 (5xx)

일시적이고 재시도 가능할 수 있는 서버 측 오류입니다.

범주 설명 예제
백엔드 오류 백엔드 서비스 문제 연결 거부, 백엔드 타임아웃
라우터 오류 내부 라우터 문제 설정 오류, 패닉
인프라 오류 인프라 장애 데이터베이스 다운, 네트워크 파티션
용량 오류 리소스 고갈 메모리 제한, 연결 풀 가득 참

HTTP 상태 코드

성공 코드 (2xx)

상태 이름 설명 사용 시기
200 OK 요청이 성공적으로 완료됨 일반 응답
201 Created 리소스가 성공적으로 생성됨 리소스 생성
202 Accepted 처리를 위해 요청이 수락됨 비동기 작업
204 No Content 응답 본문 없이 성공 삭제

클라이언트 오류 코드 (4xx)

상태 이름 설명 사용 시기
400 Bad Request 잘못된 요청 형식 잘못된 JSON, 누락된 필드
401 Unauthorized 인증 필요 누락되거나 잘못된 인증
403 Forbidden 접근 거부 불충분한 권한
404 Not Found 리소스를 찾을 수 없음 모델/엔드포인트 사용 불가
405 Method Not Allowed HTTP 메서드 지원되지 않음 잘못된 HTTP 동사
408 Request Timeout 클라이언트 요청 타임아웃 느린 클라이언트
413 Payload Too Large 요청 본문이 너무 큼 크기 제한 초과
422 Unprocessable Entity 유효성 검사 실패 비즈니스 로직 오류
429 Too Many Requests 속도 제한 초과 속도 제한

서버 오류 코드 (5xx)

상태 이름 설명 사용 시기
500 Internal Server Error 예상치 못한 서버 오류 처리되지 않은 예외
501 Not Implemented 기능이 구현되지 않음 지원되지 않는 작업
502 Bad Gateway 잘못된 백엔드 응답 백엔드 오류
503 Service Unavailable 서비스가 일시적으로 다운 모든 백엔드 비정상
504 Gateway Timeout 백엔드 타임아웃 백엔드가 너무 느림
507 Insufficient Storage 스토리지 가득 참 디스크/메모리 가득 참

오류 응답 형식

표준 오류 응답

{
  "error": {
    "code": 404,
    "type": "model_not_found",
    "message": "정상 백엔드에서 모델 'gpt-5'를 찾을 수 없습니다",
    "details": {
      "requested_model": "gpt-5",
      "available_models": ["gpt-4", "gpt-3.5-turbo", "llama2"],
      "backends_checked": 3,
      "healthy_backends": 2
    },
    "request_id": "req_12345",
    "timestamp": "2024-01-15T10:30:45Z"
  }
}

유효성 검사 오류 응답

{
  "error": {
    "code": 400,
    "type": "validation_error",
    "message": "잘못된 요청 매개변수",
    "details": {
      "validation_errors": [
        {
          "field": "messages",
          "error": "필수 필드 누락"
        },
        {
          "field": "temperature",
          "error": "0과 2 사이여야 합니다",
          "value": 3.5
        }
      ]
    },
    "request_id": "req_12346"
  }
}

속도 제한 오류 응답

{
  "error": {
    "code": 429,
    "type": "rate_limit_exceeded",
    "message": "API 속도 제한 초과",
    "details": {
      "limit": 100,
      "window": "1m",
      "retry_after": 45,
      "reset_at": "2024-01-15T10:31:30Z"
    },
    "headers": {
      "X-RateLimit-Limit": "100",
      "X-RateLimit-Remaining": "0",
      "X-RateLimit-Reset": "1705316490",
      "Retry-After": "45"
    }
  }
}

백엔드 오류 전달

백엔드가 4xx 오류를 반환하면 Continuum Router는 백엔드의 원본 오류 세부 정보를 파싱하고 전달합니다. 이를 통해 디버깅에 더 유용한 오류 정보를 제공합니다.

지원되는 백엔드 형식:

  • OpenAI API ({"error": {"message": "...", "type": "...", "param": "...", "code": "..."}})
  • Anthropic Claude API ({"error": {"message": "...", "type": "..."}})
  • Google Gemini API ({"error": {"message": "...", "status": "...", "code": ...}})

예제 응답 (백엔드 오류 전달 포함):

{
  "error": {
    "code": 400,
    "type": "invalid_request_error",
    "message": "잘못된 크기 '512x512'. gpt-image-1에 유효한 크기: 1024x1024, 1536x1024, 1024x1536, auto",
    "param": "size"
  }
}

동작:

  • 백엔드가 파싱 가능한 오류 응답을 반환하면 원본 message, type, param, code 필드가 보존됨
  • 백엔드가 제공할 때 param 필드가 포함됨 (어떤 매개변수가 오류를 일으켰는지 식별하는 데 유용)
  • 백엔드 응답을 파싱할 수 없으면 일반적인 오류 메시지 반환
  • 모든 오류 응답은 OpenAI 호환 유지

폴백 응답 (백엔드 오류를 파싱할 수 없을 때):

{
  "error": {
    "code": 400,
    "type": "invalid_request_error",
    "message": "Client error: HTTP 400"
  }
}

재시도 전략

설정

retry:
  # 기본 설정
  max_attempts: 3
  initial_delay: "100ms"
  max_delay: "10s"
  backoff_multiplier: 2.0
  jitter: true

  # 재시도 가능 조건
  retryable_status_codes:
        - 429  # Too Many Requests
        - 502  # Bad Gateway
        - 503  # Service Unavailable
        - 504  # Gateway Timeout

  retryable_errors:
        - ConnectionError
        - TimeoutError
        - TemporaryError

  # 엔드포인트별 설정
  endpoints:
    "/v1/chat/completions":
      max_attempts: 5
      timeout: "60s"
    "/v1/completions":
      max_attempts: 3
      timeout: "30s"

지수 백오프

backoff:
  type: exponential
  base: 100ms
  multiplier: 2
  max: 10s
  jitter: 0.1  # ±10% 무작위화

# 지연 계산:
# delay = min(base * multiplier^attempt + jitter, max)
#
# 시도 1: 100ms
# 시도 2: 200ms
# 시도 3: 400ms
# 시도 4: 800ms
# ...

스마트 재시도 로직

smart_retry:
  # 다른 백엔드로 재시도
  try_different_backend: true

  # 재시도 시 요청 축소
  reduce_on_retry:
    max_tokens: 0.8  # 20% 감소
    temperature: 0.9  # 온도 낮춤

  # 특정 오류에 대한 재시도 건너뛰기
  non_retryable:
        - AuthenticationError
        - ValidationError
        - PaymentRequired

서킷 브레이커

아키텍처 세부 정보

상태 머신 다이어그램, 관리자 엔드포인트, Prometheus 메트릭을 포함한 자세한 구현 아키텍처는 서킷 브레이커 아키텍처를 참조하세요.

설정

circuit_breaker:
  enabled: true

  # 장애 감지
  failure_threshold: 5        # 회로 개방까지의 실패 횟수
  success_threshold: 2        # 회로 닫힘까지의 성공 횟수

  # 타이밍
  timeout: "30s"              # 요청 타임아웃
  half_open_timeout: "15s"    # 반개방 상태 지속 시간
  reset_timeout: "60s"        # 재시도까지의 시간

  # 모니터링 윈도우
  window_size: "60s"
  min_requests: 10            # 통계를 위한 최소 요청

회로 상태

stateDiagram-v2
    [*] --> Closed
    Closed --> Open: 장애 임계값 도달
    Open --> HalfOpen: 리셋 타임아웃 만료
    HalfOpen --> Closed: 성공 임계값 도달
    HalfOpen --> Open: 장애 감지

백엔드별 서킷 브레이커

backends:
    - name: primary
    url: http://primary:8000
    circuit_breaker:
      failure_threshold: 3
      reset_timeout: "30s"

    - name: secondary
    url: http://secondary:8000
    circuit_breaker:
      failure_threshold: 5
      reset_timeout: "60s"

오류 복구

자동 복구

recovery:
  # 헬스 체크 복구
  health_checks:
    enabled: true
    interval: "30s"
    recovery_threshold: 2  # 연속 성공 횟수

  # 연결 풀 복구
  connection_pool:
    validation_interval: "60s"
    evict_invalid: true
    replace_invalid: true

  # 캐시 복구
  cache:
    clear_on_error: false
    partial_invalidation: true

모델 폴백

라우터는 기본 모델을 사용할 수 없을 때 자동 모델 폴백을 지원합니다. 이는 포괄적인 오류 복구를 위해 서킷 브레이커와 통합됩니다.

# 모델 폴백 설정
fallback:
  enabled: true

  fallback_chains:
    "gpt-4o":
      - "gpt-4-turbo"
      - "gpt-3.5-turbo"
    "claude-opus-4-5-20251101":
      - "claude-sonnet-4-5"
      - "claude-haiku-4-5"
    # 크로스 프로바이더 폴백
    "gemini-2.5-pro":
      - "gemini-2.5-flash"
      - "gpt-4o"

  fallback_policy:
    trigger_conditions:
      error_codes: [429, 500, 502, 503, 504]
      timeout: true
      connection_error: true
      circuit_breaker_open: true
    max_fallback_attempts: 3
    fallback_timeout_multiplier: 1.5

폴백 트리거 조건

조건 HTTP 상태 설명
Rate Limit 429 백엔드 속도 제한 초과
Server Error 500 내부 백엔드 오류
Bad Gateway 502 백엔드에서 잘못된 응답
Service Unavailable 503 백엔드가 일시적으로 사용 불가
Gateway Timeout 504 백엔드 요청 타임아웃
Circuit Open N/A 서킷 브레이커가 열림

폴백 응답 헤더

폴백이 발생하면 다음 헤더가 추가됩니다:

X-Fallback-Used: true
X-Original-Model: gpt-4o
X-Fallback-Model: gpt-4-turbo
X-Fallback-Reason: error_code_429
X-Fallback-Attempts: 2

폴백 오류 응답

모든 폴백이 소진되었을 때:

{
  "error": {
    "code": 503,
    "type": "all_fallbacks_exhausted",
    "message": "'gpt-4o'에 대한 모든 폴백 모델 실패",
    "details": {
      "original_model": "gpt-4o",
      "attempted_fallbacks": ["gpt-4-turbo", "gpt-3.5-turbo"],
      "failure_reasons": [
        {"model": "gpt-4-turbo", "reason": "error_code_503"},
        {"model": "gpt-3.5-turbo", "reason": "timeout"}
      ]
    },
    "request_id": "req_12345"
  }
}

우아한 성능 저하

degradation:
  # 폴백 모델 (레거시 - fallback.fallback_chains 사용 권장)
  model_fallbacks:
    "gpt-4": ["gpt-3.5-turbo", "gpt-3"]
    "claude-opus": ["claude-sonnet", "claude-haiku"]

  # 기능 저하
  features:
    streaming:
      fallback_to_non_streaming: true
    functions:
      disable_on_error: true

  # 응답 저하
  response:
    reduce_max_tokens: true
    lower_temperature: true
    simplify_prompts: true

장애 조치 전략

failover:
  strategy: priority  # 또는 round-robin, least-failures

  backends:
        - name: primary
      priority: 1
      weight: 100

        - name: secondary
      priority: 2
      weight: 50

        - name: tertiary
      priority: 3
      weight: 10

  conditions:
        - error_rate > 0.1
        - latency_p99 > 5s
        - health_score < 0.5

사용자 정의 오류 처리

오류 미들웨어

// 사용자 정의 오류 핸들러 구현
pub async fn error_handler(error: Error) -> Response {
    let (status, error_type, message) = match error {
        Error::Validation(e) => (
            StatusCode::BAD_REQUEST,
            "validation_error",
            e.to_string()
        ),
        Error::NotFound(e) => (
            StatusCode::NOT_FOUND,
            "not_found",
            e.to_string()
        ),
        Error::Backend(e) => (
            StatusCode::BAD_GATEWAY,
            "backend_error",
            "Backend service error"
        ),
        Error::Internal(e) => {
            error!("Internal error: {:?}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                "internal_error",
                "An internal error occurred"
            )
        }
    };

    Json(ErrorResponse {
        error: ErrorDetails {
            code: status.as_u16(),
            error_type: error_type.to_string(),
            message: message.to_string(),
            request_id: request_id(),
            timestamp: Utc::now(),
        }
    }).into_response()
}

오류 변환

error_transformation:
  # 백엔드 오류를 클라이언트 친화적 메시지로 매핑
  mappings:
        - backend_error: "CUDA out of memory"
      client_error: "모델을 일시적으로 사용할  없습니다. 다시 시도해 주세요"
      status: 503

        - backend_error: "Model not loaded"
      client_error: "모델 초기화 진행 중"
      status: 503
      retry_after: 30

  # 민감한 정보 숨기기
  sanitization:
    remove_stack_traces: true
    remove_internal_ips: true
    remove_credentials: true

오류 훅

error_hooks:
  # 오류 전 훅
  pre_error:
        - log_error
        - capture_metrics
        - notify_monitoring

  # 오류 후 훅
  post_error:
        - cleanup_resources
        - update_circuit_breaker
        - trigger_failover

  # 사용자 정의 핸들러
  handlers:
        - type: webhook
      url: https://alerts.example.com/errors
      events: [critical_error, repeated_error]

        - type: email
      to: oncall@example.com
      events: [service_down]

오류 디버깅

오류 로깅

logging:
  errors:
    level: debug  # 모든 오류를 상세히 로깅
    include_request_body: true
    include_response_body: true
    include_headers: true

  # 구조화된 오류 로깅
  format:
    type: json
    fields:
      - timestamp
      - level
      - error_type
      - error_message
      - request_id
      - backend_id
      - model
      - latency
      - stack_trace

디버그 엔드포인트

# 최근 오류 가져오기
curl http://localhost:8080/admin/errors/recent

# 오류 통계 가져오기
curl http://localhost:8080/admin/errors/stats

# 특정 오류 세부 정보 가져오기
curl http://localhost:8080/admin/errors/req_12345

# 테스트용 오류 트리거
curl -X POST http://localhost:8080/admin/debug/error \
  -d '{"type": "backend_timeout", "backend": "primary"}'

오류 트레이싱

tracing:
  errors:
    capture_stack_trace: true
    capture_variables: true
    capture_context: true

  # 분산 트레이싱
  propagation:
        - tracecontext
        - baggage

  # 오류 샘플링
  sampling:
    all_errors: true
    error_rate_threshold: 0.01

일반적인 오류 시나리오

시나리오 1: 모든 백엔드 다운

# 감지
condition: all_backends.health_status == unhealthy

# 응답
response:
  status: 503
  message: "서비스가 일시적으로 사용할  없습니다"
  retry_after: 30

# 복구
recovery:
    - increase_health_check_frequency
    - notify_oncall
    - attempt_backend_restart
    - switch_to_backup_region

시나리오 2: 모델을 찾을 수 없음

# 감지
condition: requested_model not in available_models

# 응답
response:
  status: 404
  message: "모델 '{model}'을 찾을  없습니다"
  suggestions: similar_models

# 완화
mitigation:
    - check_model_aliases
    - refresh_model_cache
    - try_alternative_backends

시나리오 3: 속도 제한 초과

# 감지
condition: request_count > rate_limit

# 응답
response:
  status: 429
  retry_after: calculate_backoff()
  headers:
    X-RateLimit-Remaining: 0

# 처리
handling:
    - queue_request_if_premium
    - suggest_upgrade_plan
    - apply_exponential_backoff

시나리오 4: 타임아웃

# 감지
condition: request_duration > timeout

# 응답
response:
  status: 504
  message: "요청 타임아웃"

# 완화
mitigation:
    - try_with_reduced_max_tokens
    - switch_to_faster_backend
    - enable_streaming_if_possible

시나리오 5: 백엔드 불일치

# 감지
condition: backend_response_format != expected_format

# 응답
response:
  status: 502
  message: "잘못된 백엔드 응답"

# 복구
recovery:
    - log_response_for_debugging
    - mark_backend_as_degraded
    - retry_with_different_backend
    - update_backend_adapter

시나리오 6: 파일 해결 실패

# 감지
condition: file_reference_not_found OR invalid_file_id

# 응답
response:
  status: 404  # 파일을 찾을 수 없음
  # 또는
  status: 400  # 잘못된 파일 ID 형식
  message: "파일 참조 해결 실패"
  type: "invalid_request_error"
  code: "file_resolution_failed"

# 세부 정보
details:
    - file_id: "file-abc123"
    - reason: "file not found" OR "invalid file ID format"

# 완화
mitigation:
    - verify_file_was_uploaded
    - check_file_id_format_starts_with_file_prefix
    - ensure_file_not_deleted

시나리오 7: 파일이 너무 큼

# 감지
condition: file_size > max_file_size

# 응답
response:
  status: 413
  message: "파일 크기가 최대 허용량을 초과합니다"
  type: "invalid_request_error"

# 세부 정보
details:
  file_size: 600000000  # 바이트
  max_size: 536870912   # 바이트 (512MB 기본값)

# 완화
mitigation:
    - compress_file_before_upload
    - use_smaller_file
    - increase_max_file_size_in_config

시나리오 8: 너무 많은 파일 참조

# 감지
condition: file_references_count > 20

# 응답
response:
  status: 400
  message: "요청에 파일 참조가 너무 많습니다"
  type: "invalid_request_error"

# 세부 정보
details:
  count: 25
  max_allowed: 20

# 완화
mitigation:
    - split_request_into_multiple_calls
    - reduce_number_of_files

오류 모니터링

메트릭

# 오류율
rate(http_requests_total{status=~"5.."}[5m])

# 유형별 오류율
rate(errors_total[5m]) by (error_type)

# 백엔드 오류율
rate(backend_errors_total[5m]) by (backend_id, error_type)

# 서킷 브레이커 상태
circuit_breaker_state{backend_id="primary"}

알림

alerts:
    - name: HighErrorRate
    condition: error_rate > 0.05
    duration: 5m
    severity: warning

    - name: AllBackendsDown
    condition: healthy_backends == 0
    duration: 1m
    severity: critical

    - name: CircuitBreakerOpen
    condition: circuit_breaker_state == "open"
    duration: 5m
    severity: warning

모범 사례

오류 설계

  1. 적절한 HTTP 상태 코드 사용
  2. 명확하고 실행 가능한 오류 메시지 제공
  3. 추적을 위한 요청 ID 포함
  4. 클라이언트에 내부 세부 정보 노출 금지
  5. 충분한 컨텍스트와 함께 오류 로깅

오류 처리

  1. 백오프와 함께 재시도 로직 구현
  2. 연쇄 장애 방지를 위해 서킷 브레이커 사용
  3. 적절한 타임아웃 설정
  4. 적절한 계층에서 오류 처리
  5. 복구 불가능한 오류는 빠르게 실패

오류 복구

  1. 자동 복구를 위한 헬스 체크 구현
  2. 중요한 경로에 대한 폴백 전략 사용
  3. 오류율과 패턴 모니터링
  4. 이상에 대한 알림 설정
  5. 오류 시나리오 및 복구 절차 문서화

참고 문서