콘텐츠로 이동

속도 제한 아키텍처

라우터는 남용을 방지하고 클라이언트 간 공정한 리소스 할당을 보장하기 위해 정교한 속도 제한을 구현합니다.

아키텍처

속도 제한은 이중 윈도우 방식을 사용하여 HTTP 계층에서 구현됩니다:

pub struct ModelEndpointRateLimiter {
    cache: Arc<DashMap<String, (Instant, u32, u32)>>, // (window_start, request_count, burst_count)
    window_duration: Duration,        // 지속 제한을 위한 60초
    max_requests_per_window: u32,     // 분당 100개 요청
    burst_limit: u32,                 // 최대 20개 요청
    burst_window: Duration,           // 버스트 감지를 위한 5초
}

클라이언트 식별

시스템은 우선순위 기반 클라이언트 식별 전략을 사용합니다:

  1. API 키 (선호): Bearer 토큰의 처음 16자 사용
  2. IP 주소 (폴백): 다음 순서로 헤더에서 추출:
  3. X-Forwarded-For (프록시/로드 밸런서 환경용)
  4. X-Real-IP (대체 헤더)
  5. IP를 확인할 수 없는 경우 "unknown"으로 폴백

속도 제한 규칙

각 클라이언트는 다음과 같이 독립적으로 속도 제한됩니다:

  • 지속 제한: 분당 100개 요청 (슬라이딩 윈도우)
  • 버스트 보호: 5초 윈도우 내 최대 20개 요청
  • 클라이언트별 격리: 각 API 키 또는 IP는 별도의 쿼터를 가짐

설정

rate_limiting:
  enabled: true

  # 전역 기본값
  default:
    requests_per_minute: 100
    burst_limit: 20
    burst_window_seconds: 5

  # 엔드포인트별 오버라이드
  endpoints:
    /v1/chat/completions:
      requests_per_minute: 60
      burst_limit: 10
    /v1/models:
      requests_per_minute: 300
      burst_limit: 50

  # 클라이언트별 오버라이드 (API 키 접두사로)
  clients:
    sk-premium-*:
      requests_per_minute: 500
      burst_limit: 100
    sk-free-*:
      requests_per_minute: 20
      burst_limit: 5

캐시 관리

속도 제한기에는 자동 정리 메커니즘이 포함됩니다:

  • 메모리 효율성: 락프리 동시 접근을 위한 DashMap
  • 자동 정리: 캐시 > 1000 항목 시 만료된 항목 제거
  • TTL 차별화:
    • 빈 모델 응답: 5초 캐시 TTL (DoS 방지)
    • 일반 응답: 60초 캐시 TTL

보안 고려 사항

속도 제한 시스템은 여러 보안 문제를 해결합니다:

  1. DoS 방지: 빈 응답에 대한 짧은 TTL로 캐시 포이즈닝 방지
  2. 공정한 리소스 할당: 클라이언트별 제한으로 독점 방지
  3. 버스트 보호: 이중 윈도우 방식으로 지속적 공격과 버스트 공격 모두 포착
  4. 클라이언트 스푸핑 완화: IP 주소보다 API 키 우선

메트릭 및 모니터링

속도 제한은 메트릭 시스템과 통합됩니다:

pub struct ModelMetrics {
    pub rate_limit_violations: AtomicU64,  // 거부된 요청 추적
    pub empty_responses_returned: AtomicU64, // 빈 응답 비율 모니터링
    pub transient_errors: AtomicU64,       // 네트워크/타임아웃 실패
    pub permanent_errors: AtomicU64,       // 인증/설정 실패
}

Prometheus 메트릭

# 속도 제한 위반
rate_limit_violations_total{client_id="sk-abc...", endpoint="/v1/chat/completions"} 15

# 현재 요청 수
rate_limit_current_requests{client_id="sk-abc...", window="minute"} 45
rate_limit_current_requests{client_id="sk-abc...", window="burst"} 8

# 속도 제한 상태
rate_limit_remaining{client_id="sk-abc...", window="minute"} 55

응답 헤더

속도 제한 정보는 응답 헤더에 포함됩니다:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 55
X-RateLimit-Reset: 1699574460
X-RateLimit-Burst-Limit: 20
X-RateLimit-Burst-Remaining: 12

오류 응답

속도 제한이 적용되면 API는 다음을 반환합니다:

{
  "error": {
    "message": "속도 제한 초과. 45초 후에 다시 시도하세요.",
    "type": "rate_limit_exceeded",
    "code": 429,
    "details": {
      "limit": 100,
      "remaining": 0,
      "reset_at": "2024-01-15T10:30:00Z",
      "retry_after": 45
    }
  }
}

구현 세부 사항

속도 제한기는 싱글톤 서비스로 구현됩니다:

static MODEL_RATE_LIMITER: once_cell::sync::Lazy<ModelEndpointRateLimiter> =
    once_cell::sync::Lazy::new(ModelEndpointRateLimiter::new);

이를 통해: - 단일 속도 제한 적용 지점 - 모든 요청 핸들러에서 일관된 상태 - 최소 메모리 오버헤드

관련 문서