콘텐츠로 이동

섀도 트래픽

섀도 트래픽 미러링은 실제 클라이언트 요청 중 일부를 샘플링하여 두 번째 모델로 재전송합니다. 클라이언트가 받는 응답은 그대로 유지됩니다. 이 기능은 모델 실험으로는 답할 수 없는 질문에 답합니다. 후보 모델이 이미 주 모델이 처리 중인 트래픽에서 어떻게 동작하는지 확인할 수 있습니다.

모델 실험은 실시간 트래픽을 나누므로, 후보 모델은 배정받은 비율의 요청에서만 평가됩니다. 섀도 트래픽은 대신 일치하는 모든 요청을 기존과 동일하게 주 모델로 보내고, 주 요청이 디스패치된 뒤 동일한 요청을 섀도 모델에 한 번 더 보냅니다. 두 응답은 같은 프롬프트에서 만들어지며, 클라이언트에는 주 응답만 전달됩니다.

미러링은 기본적으로 꺼져 있습니다. shadow 섹션이 없거나 enabled: false이면 요청 처리 방식은 달라지지 않습니다.

설정

shadow:
  enabled: true
  sample_rate: 0.05            # 일치하는 요청 중 0.0 ~ 1.0 비율
  models: ["chat", "gpt-5.6-sol"]   # 미러링할 클라이언트 모델 이름 (비어 있으면 전체)
  target:
    model: gpt-5.6-luna        # 일반 라우팅 파이프라인이 해석하는 모델 이름
    # backend: azure-eu        # 선택: 백엔드 고정, 미설정 시 일반 선택
  max_request_bytes: 65536
  max_concurrent: 8            # 동시 섀도 요청 수, 초과분은 드롭
  timeout: 60s
  stream: false                # 스트리밍 섀도 응답은 누적하지 않고 소진
  headers: strip               # 클라이언트 인증 및 테넌트 헤더 제거
  sample_key: api_key          # 결정적 샘플링 키: api_key | user | none
필드 기본값 설명
enabled false 전체 스위치입니다. 꺼져 있으면 섹션은 검증되지만 미러링은 수행되지 않습니다.
sample_rate 0.0 일치하는 요청 중 미러링할 비율이며 0.0 에서 1.0 사이입니다. 0.0은 미러링하지 않고 1.0은 일치하는 모든 요청을 미러링합니다.
models [] 미러링할 클라이언트 모델 이름이며, 요청이 담고 있는 이름과 비교합니다. 비어 있으면 모든 모델을 미러링합니다.
target.model 활성화 시 필수 미러링 요청이 사용할 모델입니다. 일반 라우팅 파이프라인이 해석합니다.
target.backend 미설정 선택적 백엔드 고정입니다. 미설정이면 일반 선택을 사용합니다. 고정할 백엔드는 설정에 존재하고 사용자 라우팅이 가능해야 합니다.
max_request_bytes 65536 인코딩된 본문이 이보다 크면 해당 요청은 건너뛰고 skipped_size로 집계합니다.
max_concurrent 8 라우터별 동시 미러 수이며 최소 1입니다. 빈 슬롯이 없으면 대기하지 않고 드롭합니다.
timeout "60s" 섀도 요청 한 번의 전체 시간 상한이며 본문 읽기도 포함합니다.
stream false 참이면 스트리밍 섀도 응답을 누적하지 않고 소진합니다. 거짓이면 섀도 요청은 버퍼링 응답을 요구합니다.
headers strip 클라이언트 헤더 처리 방식입니다. strip만 허용하며, 라우터는 클라이언트 자격 증명을 섀도 백엔드로 전달하지 않습니다.
sample_key api_key 샘플링 판단의 기준입니다. 아래 샘플링 항목을 참고하십시오.

미러링이 하는 일과 하지 않는 일

미러는 주 요청이 디스패치된 뒤 분리된 태스크에서 실행됩니다. 클라이언트가 관찰하는 값은 바뀌지 않습니다.

  • 주 응답의 상태 코드와 헤더는 섹션이 없을 때와 동일합니다.
  • 클라이언트가 체감하는 지연은 그대로입니다. 미러는 요청 경로에서 대기하지 않습니다.
  • 어떤 형태의 섀도 실패든 메트릭으로 기록되고 클라이언트에 노출되지 않습니다.

미러는 라우터 내부 집계에서도 분리되어 있습니다.

  • 클라이언트 속도 제한 쿼터를 소비하지 않습니다. 미러는 HTTP 계층으로 다시 들어가지 않으므로 클라이언트 속도 제한 미들웨어가 이를 보지 않습니다.
  • 모델별, 백엔드별 속도 제한 버킷을 소비하지 않습니다. 선택은 동일한 전략 파이프라인을 거치지만, 디스패치 요청이 차감하는 버킷을 차감하지 않습니다.
  • 주 백엔드의 서킷 상태를 어느 방향으로도 바꾸지 않습니다. 미러는 성공, 실패, 타임아웃 어느 것도 기록하지 않습니다. 다만 선택 단계에서는 열린 서킷을 존중하므로, 라우터가 현재 회피 중인 백엔드로 미러를 보내지 않습니다.
  • 사용량 행이나 통계 행을 기록하지 않습니다.

클라이언트 헤더

미러는 정제된 헤더 맵을 전송합니다. 섀도 백엔드는 자체 설정의 자격 증명으로 인증하며, 클라이언트가 보낸 값은 사용하지 않습니다.

제거 그룹 헤더
자격 증명 authorization, x-api-key, api-key, x-goog-api-key, cookie, set-cookie, proxy-authorization, x-auth-token, x-access-token
라우터 소유 귀속 anthropic-user-profile-id, x-continuum-resolved-user-profile-id
클라이언트 신원 및 테넌트 x-user-id, x-tenant, x-org-id
라우터 제어 및 포워딩 x-backend, x-continuum-*, x-forwarded-for, x-forwarded-host, x-forwarded-proto, x-real-ip, forwarded, x-vllm-priority
프레이밍 및 홉 단위 host, connection, keep-alive, transfer-encoding, content-length, content-type, accept-encoding, upgrade, te, trailer, proxy-connection

그 밖의 클라이언트 헤더는 그대로 전달합니다. 제거 목록을 전달하는 모드는 제공하지 않습니다. 헤더 이름은 _를 -로 바꾸어 대소문자 구분 없이 일치시키므로, 클라이언트의 x_api_key는 x-api-key처럼 제거됩니다.

샘플링

샘플링 판단은 복사가 일어나기 전에 수행되므로, 일치하지 않거나 샘플링되지 않은 요청은 미러에 아무 비용도 들이지 않습니다.

  • sample_key: api_key는 인증된 API 키 ID의 안정적인 64비트 해시로 샘플링합니다.
  • sample_key: user는 해석된 사용자 신원의 안정적인 64비트 해시로 샘플링합니다.
  • sample_key: none은 요청마다 무작위로 샘플링합니다.

결정적 키는 프로세스 재시작과 여러 레플리카에 걸쳐 동일하게 유지되므로, 동일한 sample_rate에서 한 번 샘플링된 호출자는 계속 샘플링됩니다. 인증 없이 동작하는 라우터처럼 설정된 키에 해당하는 신원이 없으면, 요청을 건너뛰지 않고 무작위 판단으로 대체합니다.

요청이 샘플링된 뒤에는 본문을 복사하기 전에 크기를 측정하므로, max_request_bytes를 넘는 샘플링 대상 요청은 skipped_size로 집계되고 재전송되지 않습니다.

동시성과 타임아웃

각 미러는 라우터의 max_concurrent 슬롯 하나를 사용합니다. 모든 슬롯이 사용 중이면 미러는 드롭되고 shed로 집계됩니다. 대기열이 없으므로 느린 섀도 모델이 무한한 백로그를 만들지 않습니다. 슬롯은 주 요청이 아직 실행 중일 때가 아니라 미러의 시도가 시작될 때 확보되며, 본문 읽기가 끝날 때까지 유지됩니다.

timeout은 시도 한 번의 끝에서 끝까지를 제한합니다. 시간이 만료된 미러는 timeout으로 집계되고 연결이 종료됩니다.

스트리밍

스트리밍 클라이언트 요청도 버퍼링 요청과 동일하게 미러링됩니다. stream: true이면 섀도 요청이 백엔드에 스트림을 요구하고, 응답은 분리된 태스크에서 청크 단위로 소진됩니다. 따라서 라우터는 완성된 섀도 응답 전체를 메모리에 보관하지 않습니다. stream: false이면 섀도 요청은 버퍼링 응답을 요구하고, 토큰 수를 읽은 뒤 폐기합니다.

클라이언트의 스트림은 별도의 응답이며 절대 변경되지 않습니다.

메트릭

메트릭 레이블 의미
router_shadow_requests_total result 고려된 미러마다 한 번 증가합니다. result는 mirrored(디스패치 후 2xx 응답), skipped_size, shed, timeout, error 중 하나입니다.
router_shadow_latency_seconds model, backend 섀도 디스패치부터 섀도 응답 종료까지의 시간입니다.
router_shadow_usage_tokens_total model, backend, kind 섀도 응답이 보고한 토큰 수입니다. kind는 prompt 또는 completion입니다.

model과 backend는 모두 설정에서 오므로, 카디널리티는 트래픽이 아니라 설정된 대상 수로 제한됩니다. 메트릭 패밀리는 시작 시 등록되므로, 섹션을 활성화하지 않은 라우터도 0 값으로 보고합니다.

개인정보

프롬프트와 완성 내용은 로그에 남지 않으며 메트릭 레이블로도 사용되지 않습니다. 미러의 로그 줄에는 설정된 대상 모델, 요청된 모델 이름, 선택된 백엔드, 응답 성공 여부, 지연만 기록됩니다. 헤더 값은 기록하지 않습니다.

핫 리로드

섹션은 각 요청이 실행되는 설정 세대에서 읽으므로, 샘플링 비율, 대상, 동시성 상한, 타임아웃 변경은 다음 요청부터 적용됩니다. shadow를 비활성화하면 새 미러는 즉시 중단되며, 이미 진행 중인 미러는 완료될 수 있습니다.

관련 문서

  • 모델 실험: 실시간 트래픽을 변형 간에 나누는 방법입니다.
  • 메트릭: 스크레이프 엔드포인트와 노출되는 메트릭 패밀리입니다.
  • 속도 제한: 미러가 의도적으로 우회하는 클라이언트 및 모델별 쿼터입니다.
  • 서킷 브레이커: 미러가 변경하지 않는 상태입니다.