성능 가이드¶
이 가이드는 실제 구현된 성능 제어 항목과 측정 우선 튜닝 절차를 설명합니다. 종단 간 지연과 처리량은 주로 선택한 모델, 제공자, 네트워크, 요청 크기, 스트리밍 동작, 활성 미들웨어, 호스트 한도에 따라 달라집니다. 프로젝트는 모든 환경에 적용되는 초당 요청 수나 메모리 목표를 보장하지 않습니다.
튜닝 전 측정¶
저장소의 benches/ 아래에 Criterion 벤치마크가 있습니다.
프로덕션과 동일한 대상 및 기능 세트에서 실행하십시오. HTTP 부하 테스트에는 실제 요청 본문, 인증 모드, 백엔드 구성을 사용해야 합니다. /health 벤치마크는 프록시 트래픽을 대표하지 않습니다.
wrk POST 스크립트 예시:
-- scripts/chat_completion.lua
wrk.method = "POST"
wrk.body = '{"model":"gpt-5.4-nano","messages":[{"role":"user","content":"Hello"}]}'
wrk.headers["Content-Type"] = "application/json"
wrk -t12 -c400 -d30s --latency \
-s scripts/chat_completion.lua \
http://localhost:8080/v1/chat/completions
같은 요청을 백엔드에 직접 보내 기준값을 만드십시오. 다른 호스트에서 복사한 수치보다 직접 호출과 라우터 경유 호출의 차이가 더 의미 있습니다.
SSE 파이프라인 벤치마크¶
모든 /v1/chat/completions SSE 응답은 청크 기한, UTF-8 경계 처리, SSE 파싱, 추론 필드 정규화, 오류 변환, keep-alive 삽입, 직렬화를 위한 공통 build_sse_pipeline 어댑터를 사용합니다.
Apple M1 Ultra(macOS 26.5, rustc 1.95, 벤치마크 스레드 1개)에서 저장소 벤치마크를 실행한 결과는 다음과 같습니다.
| 청크 | 단순 스트림 | 전체 파이프라인 | 파이프라인 비용 | 청크당 |
|---|---|---|---|---|
| 64 | 5.36 µs | 54.8 µs | 49.4 µs | 0.77 µs |
| 512 | 42.5 µs | 429 µs | 387 µs | 0.76 µs |
| 4096 | 349 µs | 3.47 ms | 3.12 ms | 0.76 µs |
이는 단일 호스트의 마이크로벤치마크 결과이며 서비스 수준 보장이 아닙니다. 배포할 릴리스, 컴파일러, 아키텍처, 기능 세트에서 다시 측정하십시오.
애플리케이션 제어 항목¶
연결 풀¶
server.connection_pool_size는 백엔드마다 유지할 최대 유휴 HTTP 연결 수를 설정합니다. 측정 결과 연결 churn 또는 재사용 부족이 확인될 때만 늘리십시오. 유휴 연결도 자원을 사용합니다.
일회성 CLI 덮어쓰기는 다음과 같습니다.
라우터는 시작할 때 백엔드 연결을 미리 준비합니다. 공유 HTTP 클라이언트 재사용은 핸드셰이크 비용을 줄이지만 실제 효과는 제공자와 네트워크에 따라 달라집니다.
백엔드 선택¶
최상위 selection_strategy 필드를 사용하십시오. routing.strategy는 프로덕션 백엔드 선택 제어가 아닙니다.
selection_strategy: LeastLatency
backends:
- name: primary
url: http://backend-1:8000
weight: 3
- name: secondary
url: http://backend-2:8000
weight: 1
사용 가능한 값:
RoundRobinWeightedRoundRobinLeastLatencyRandomConsistentHashPrefixAwareHash
LeastLatency는 관측된 백엔드 지연을 사용합니다. WeightedRoundRobin은 각 백엔드의 weight를 사용합니다. ConsistentHash는 안정적인 affinity를 제공하고, PrefixAwareHash는 프롬프트 접두사 affinity와 prefix_routing 설정을 사용해 분산 KV 캐시 재사용을 높입니다.
시간 초과¶
느린 제공자 작업을 기다리는 것보다 포기하는 편이 나을 때만 시간 초과를 줄이십시오. 클라이언트 전체 기한은 라우터 재시도 및 요청 예산보다 길게 설정하십시오.
timeouts:
connection: 10s
request:
standard:
first_byte: 30s
total: 180s
streaming:
first_byte: 60s
chunk_interval: 30s
total: 600s
재시도¶
재시도는 일시적 장애 복구를 개선하지만 작업량과 꼬리 지연을 늘립니다. 제공자 안정성을 검증한 뒤 저지연 배포에서 시도 횟수를 줄일 수 있습니다.
retry:
max_attempts: 2
initial_delay: 100ms
max_delay: 2s
backoff_multiplier: 2.0
jitter: true
retryable_status_codes: [429, 502, 503, 504]
retryable_errors: [ConnectionError, TimeoutError]
timeout: 10s
상태 확인¶
검사 주기가 짧으면 장애를 더 빨리 감지하지만 주기적인 제공자 트래픽이 늘어납니다.
응답 캐시¶
선택적 응답 캐시는 적격 결정론 요청을 제공해 백엔드 호출을 줄일 수 있습니다. 측정된 항목 크기와 적중률을 기준으로 크기를 정하십시오.
Redis 및 계층형 백엔드는 해당 빌드 기능과 설정이 필요합니다. 활성화 전 고급 설정을 참고하십시오.
모델 목록 캐시¶
모델 집계는 60초 하드 TTL, 80% 소프트 TTL, stale-while-revalidate, 요청 병합, 10초 백그라운드 검사 주기, 제한된 빈 결과 백오프를 사용합니다. 이 내부 값은 설정할 수 없습니다. POST /v1/models/refresh는 속도 제한된 즉시 새로고침을 수행합니다.
프로필 예시¶
다음은 출발점일 뿐 모든 환경의 최적값이 아닙니다. 각 프로필을 continuum-router config validate와 대표 부하 테스트로 검증하십시오.
낮은 꼬리 지연¶
selection_strategy: LeastLatency
server:
bind_address: 0.0.0.0:8080
connection_pool_size: 100
retry:
max_attempts: 1
initial_delay: 100ms
max_delay: 1s
backoff_multiplier: 2.0
jitter: true
retryable_status_codes: [429, 502, 503, 504]
retryable_errors: [ConnectionError, TimeoutError]
timeout: 5s
health_checks:
enabled: true
interval: 10s
timeout: 5s
unhealthy_threshold: 3
healthy_threshold: 2
작은 유휴 자원 사용량¶
높은 동시성¶
server:
connection_pool_size: 500
# 도착뿐 아니라 상주도 묶습니다. 컨테이너 메모리 상한을 기준으로 잡으십시오.
# 배포 가이드의 용량 산정 절을 참고하십시오.
max_concurrent_requests: 256
rate_limiting:
enabled: true
storage: memory
프로덕션에서는 부분 블록을 그대로 복사하지 말고 속도 제한 정책을 완성하십시오. 속도 제한을 참고하십시오. connection_pool_size는 백엔드별 아웃바운드 풀이라 인바운드 동시성을 묶지 않습니다. 그 역할은 max_concurrent_requests가 하며, 상한을 넘으면 대기열에 넣지 않고 503과 Retry-After로 흘려보냅니다. 컨테이너 메모리 상한도 같은 변경에서 함께 올리십시오. 둘은 하나의 결정입니다.
Prometheus 모니터링¶
metrics로 컴파일하고 런타임에서 활성화하면 설정된 엔드포인트에서 Prometheus 메트릭을 제공합니다.
metrics:
enabled: true
endpoint: /metrics
auth:
enabled: true
username: metrics
password: "${METRICS_PASSWORD}"
유용한 메트릭:
http_requests_totalhttp_request_duration_secondsbackend_healthybackend_current_loadhttp_active_connections
기능 제한 서브시스템은 컴파일되고 활성화된 경우에만 메트릭을 추가하므로 대시보드를 만들기 전 실행 중인 /metrics 출력을 확인하십시오.
쿼리 예시:
rate(http_requests_total[5m])
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
backend_healthy
backend_current_load
운영체제 한도¶
높은 동시성에서는 변경 전에 파일 디스크립터와 listen backlog 한도를 확인하십시오.
호스트 수준 sysctl 또는 보안 한도 변경은 운영체제, 커널, 컨테이너 런타임, 트래픽 패턴에 맞게 테스트한 후 적용하십시오. 프로젝트는 하나의 보편적인 커널 튜닝 프로필을 요구하지 않습니다.
병목 진단¶
높은 지연¶
- 동일한 요청을 선택된 백엔드에 직접 보내 비교합니다.
- Admin 자격 증명으로
/admin/health와/admin/circuit/all을 확인합니다. http_request_duration_seconds와 백엔드 지연/부하 메트릭을 확인합니다.- 재시도 및 시간 초과 예산이 꼬리 지연을 배가하지 않는지 확인합니다.
- 필요한 범위에만 일시적으로
RUST_LOG=continuum_router=debug를 사용하고 비밀을 기록하지 않습니다.
높은 메모리 사용량¶
- 워크로드를 재현하며 상주 메모리를 측정합니다.
- 요청 속도보다 먼저 동시 처리 중인 요청 수를 봅니다. 최악의 상주 메모리는 동시성 곱하기 요청당 예산이며, 속도 제한은 단위 시간당 도착을 묶을 뿐 동시에 상주하는 수를 묶지 않습니다. 평균 30초라면 초당 10건은 약 300건이 동시에 떠 있다는 뜻입니다. 컨트롤 플레인 supply 보고의
active_requests와 in-flight 게이지를 확인하십시오. server.max_concurrent_requests가 비어 있다면 설정합니다. 이 값이 없으면 동시성 항을 묶는 것이 아무것도 없으므로, 요청당 예산이 프로세스 단위 상한을 전혀 함의하지 못합니다. 요청당 항목과 계산은 용량 산정: 메모리를 참고하십시오.- 요청/응답 크기, 동시 스트림, 응답 캐시 용량을 확인합니다. Files API 전송은 디스크로 스트리밍되어
files.max_file_size와 무관하게 건당 64 KiB 버퍼만 쓰므로, 단일 메모리 항목 중 가장 큰 것은 요청당 해석된 파일 내용(원본 32 MiB, base64 확장 후 약 43 MiB)입니다. response_cache.capacity를 줄이거나 응답 캐시를 비활성화해 비교합니다.- 플랫폼에 맞는 할당자/프로파일러로 릴리스 바이너리를 분석합니다.
모델 목록 캐시 용량은 내부 값이며 설정할 수 없습니다.
낮은 처리량¶
- 제공자 처리량을 직접 비교합니다.
- 속도 제한 거부, 서킷 상태, 백엔드 상태, 진행 중 부하를 확인합니다.
connection_pool_size를 늘리기 전에 연결 재사용과 파일 디스크립터 한도를 확인합니다.- 스트리밍과 비스트리밍 워크로드를 별도로 테스트합니다.
- 공유 상태/스토리지 선택이 다중 인스턴스에 적합한지 확인한 뒤 수평 확장합니다.