429/용량 오류: 계정 로테이션의 올바른 예상과 모델 용량 고갈의 오해
이 과정을 통해 할 수 있는 것
- "할당량 부족"과 "상류 속도 제한"을 올바르게 구분하여 오해 방지
- Antigravity Tools의 자동 로테이션 메커니즘과 예상 동작 이해
- 429 오류 발생시 빠르게 문제를 찾아내고 구성을 최적화하는 방법 숙지
현재 겪고 있는 문제
- 429 오류가 반환되면 "모델 용량이 없다"고 오해함
- 여러 계정을 구성했지만 여전히 자주 429를 만나고, 구성 문제인지 계정 문제인지 알 수 없음
- 시스템이 언제 자동으로 계정을 전환하는지, 언제 "멈추는지" 확실하지 않음
핵심 원리
429 오류란?
429 Too Many Requests는 HTTP 상태 코드입니다. Antigravity Tools에서 429는 "요청이 너무 잦음"만을 의미하는 것이 아니라, 할당량 고갈, 모델 일시적 과부하 등 "일시적으로 사용할 수 없음"을 나타내는 신호일 수도 있습니다.
프록시는 429 원인 식별을 시도합니다
프록시는 응답 본문에서 error.details[0].reason 또는 error.message를 구문 분석하여 429를 대략적으로 몇 가지 유형으로 분류합니다(실제로는 반환된 결과를 기준으로 함):
| 프록시 식별 유형 | 일반적인 reason / 단서 | 전형적 특징 |
|---|---|---|
| 할당량 고갈 | QUOTA_EXHAUSTED / 텍스트에 exhausted, quota 포함 | 할당량이 새로고침될 때까지 기다려야 할 수 있음 |
| 속도 제한 | RATE_LIMIT_EXCEEDED / 텍스트에 per minute, rate limit, too many requests 포함 | 보통 수십 초 수준의 냉각 |
| 모델 용량 부족 | MODEL_CAPACITY_EXHAUSTED / 텍스트에 model_capacity 포함 | 일반적으로 일시적 과부하, 나중에 복구 가능 |
| 알 수 없음 | 구문 분석 불가 | 기본 냉각 정책 사용 |
Antigravity Tools의 자동 처리
단일 요청이 429(및 일부 5xx/과부하 상태)를 만나면 프록시는 일반적으로 서버 측에서 두 가지 작업을 수행합니다:
- 냉각 시간 기록: 이 오류를
RateLimitTracker에 기록하여 후속 계정 선택 시 "여전히 냉각 중인" 계정을 능동적으로 피합니다. - 재시시에서 계정 로테이션: Handlers는 단일 요청 내에서 여러 번 시도하며, 재시시에는
force_rotate=true로 설정하여 TokenManager가 다음 사용 가능한 계정을 선택하도록 트리거합니다.
계정 전환 여부를 어떻게 알 수 있나요?
요청 본문이 변경되지 않더라도 응답에는 보통 X-Account-Email(및 X-Mapped-Model)이 포함되어 있으므로 이를 사용하여 "이번 요청에 어떤 계정이 사용되었는지" 확인할 수 있습니다.
429 오류는 언제 발생하나요?
시나리오 1: 단일 계정 요청 속도가 너무 빠름
현상: 단일 계정만 있어도 짧은 시간 내에 대량의 요청을 보내면 429가 트리거됩니다.
원인: 각 계정에는 자체 속도 제한(RPM/TPM)이 있으며 초과하면 속도 제한됩니다.
해결:
- 계정 수 증가
- 요청 빈도 낮추기
- 고정 계정 모드 사용하여 부하 분산(자세한 내용은 "고정 계정 모드" 참조)
시나리오 2: 모든 계정이 동시에 속도 제한됨
현상: 여러 계정이 있지만 모든 계정이 429를 반환합니다.
원인:
- 계정 총수가 요청 빈도를 지원하기에 충분하지 않음
- 모든 계정이 거의 동시에 속도 제한/과부하 트리거
해결:
- 더 많은 계정 추가
- 스케줄링 모드를 "성능 우선"으로 조정(스티키 세션 및 60초 창 재사 건너뜀)
- 할당량 보호가 사용 가능한 계정을 잘못 제외했는지 확인
시나리오 3: 계정이 할당량 보호에 의해 오해 판정됨
현상: 특정 계정의 할당량이 충분한데 시스템이 계속해서 건너뜁니다.
원인:
- 할당량 보호가 활성화되어 있고 임계값이 너무 높게 설정됨
- 해당 계정의 특정 모델 할당량이 임계값보다 낮음
- 계정이 수동으로
proxy_disabled로 표시됨
해결:
- 할당량 보호 설정 확인(Settings → Quota Protection), 사용 강도에 따라 임계값과 모니터링 모델 조정
- 계정 데이터에서
protected_models확인, 보호 정책에 의해 건너뛰는지 확인
따라 해보세요
1단계: 429 오류 유형 식별
이유: 다른 유형의 429 오류는 다른 처리 방식이 필요합니다.
Proxy Monitor에서 429 오류의 응답 본문을 보고 두 가지 정보에 중점을 둡니다:
- 원인:
error.details[0].reason(예:RATE_LIMIT_EXCEEDED,QUOTA_EXHAUSTED) 또는error.message - 대기 시간:
RetryInfo.retryDelay또는details[0].metadata.quotaResetDelay(존재하는 경우)
{
"error": {
"details": [
{
"reason": "RATE_LIMIT_EXCEEDED",
"metadata": {
"quotaResetDelay": "42s"
}
}
]
}
}예상 결과:
- 응답 본문에서 대기 시간(예:
RetryInfo.retryDelay또는quotaResetDelay)을 찾을 수 있으면 프록시는 보통 짧은 시간 동안 기다린 후 재시도합니다. - 대기 시간이 없으면 프록시는 내장 정책에 따라 해당 계정에 "냉각 기간"을 추가하고 재시시에서 즉시 다음 계정으로 전환합니다.
2단계: 계정 스케줄링 구성 확인
이유: 스케줄링 구성은 계정 로테이션 빈도와 우선순위에 직접적인 영향을 미칩니다.
API Proxy 페이지로 이동하여 스케줄링 정책을 확인하세요:
| 구성 항목 | 설명 | 기본값/권장 |
|---|---|---|
| Scheduling Mode | 스케줄링 모드 | Balance(기본값) |
| Preferred Account | 고정 계정 모드 | 선택되지 않음(기본값) |
스케줄링 모드 비교:
| 모드 | 계정 재사용 정책 | 속도 제한 처리 | 적용 시나리오 |
|---|---|---|---|
| CacheFirst | 스티키 세션 및 60초 창 재사 사용 활성화 | 우선 대기, Prompt Caching 적중률 크게 향상 | 대화형/높은 캐시 적중률 필요 |
| Balance | 스티키 세션 및 60초 창 재사 사용 활성화 | 즉시 대체 계정으로 전환, 성공률과 성능 균형 | 일반 시나리오, 기본값 |
| PerformanceFirst | 스티키 세션 및 60초 창 재사 건너뜀, 순수 라운드 로빈 모드 | 즉시 전환, 계정 부하 가장 균형 | 고동시성, 무상태 요청 |
캐시 우선 vs 균형 모드
Prompt Caching를 사용하고 캐시 적중률을 높이려면 CacheFirst를 선택하세요 — 속도 제한 시 즉시 계정 전환 대신 우선 대기합니다. 요청 성공률을 더 중요하게 생각하면 Balance를 선택하세요 — 속도 제한 시 즉시 계정 전환합니다.
성능 우선 모드
요청이 무상태(예: 이미지 생성, 독립 쿼리)인 경우 PerformanceFirst를 시도해 보세요. 스티키 세션 및 60초 창 재사 건너뜀으로 연속 요청이 다른 계정으로 쉽게 떨어지게 합니다.
3단계: 계정 로테이션이 정상 작동하는지 확인
이유: 시스템이 자동으로 계정을 전환할 수 있는지 확인합니다.
방법 1: 응답 헤더 보기
curl 또는 자신의 클라이언트로 응답 헤더를 인쇄하고 X-Account-Email이 변경되는지 관찰합니다.
방법 2: 로그 보기
로그 파일(시스템 위치에 따라 다름)을 열고 🔄 [Token Rotation]을 검색합니다:
🔄 [Token Rotation] Accounts: [
"[email protected](protected=[])",
"[email protected](protected=[])",
"[email protected](protected=[])"
]방법 3: Proxy Monitor 사용
Monitor 페이지에서 요청 로그를 확인하고 다음을 중점적으로 봅니다:
- Account 필드가 다른 계정 간에 전환되는지
- Status가 429인 요청 후, 성공한 요청이 다른 계정을 사용했는지
예상 결과:
- 특정 계정이 429를 반환한 후 후속 요청이 자동으로 다른 계정으로 전환됩니다.
- 여러 요청이 동일한 계정을 사용하고 모두 실패하면 스케줄링 구성 문제일 수 있습니다.
4단계: 계정 우선순위 최적화
이유: 시스템이 높은 할당량/높은 등급 계정을 우선 사용하도록 하여 429 확률을 줄입니다.
TokenManager에서 시스템은 계정 선택 전 계정 풀에 대해 한 번 정렬을 수행합니다(🔄 [Token Rotation] Accounts: ...를 인쇄함):
- 구독 등급 우선: ULTRA > PRO > FREE
- 할당량 백분율 우선: 동일 등급 내에서 할당량이 높은 순
- 정렬 진입점: 이 정렬은 프록시 측에서 발생하며, 최종적으로 어떤 계정을 사용하는지는 프록시 측 정렬 + 가용성 판단을 기준으로 합니다.
스마트 정렬 원리(프록시 측)
우선순위는 ULTRA > PRO > FREE입니다. 동일 구독 등급 내에서 remaining_quota(계정 최대 남은 할당량 백분율) 기준 내림차순입니다.
작업:
- 계정을 드래그하여 표시 순서 조정(선택 사항)
- 할당량 새로고침(Accounts → 모든 할당량 새로고침)
- 계정의 구독 등급과 할당량 확인
일반적인 문제
❌ 오류 1: 429를 "모델 용량 부족"으로 오해
현상: 429 오류를 보면 모델 용량이 부족하다고 생각합니다.
올바른 이해:
- 429는 속도 제한이지 용량 문제가 아님
- 계정을 추가하면 429 확률을 낮출 수 있음
- 스케줄링 모드를 조정하면 전환 속도를 높일 수 있음
❌ 오류 2: 할당량 보호 임계값이 너무 높게 설정됨
현상: 할당량이 충분한데 시스템이 계속 계정을 건너뜁니다.
원인: Quota Protection은 임계값보다 낮은 모델을 계정의 protected_models에 추가하고, 프록시는 스케줄링 시 "보호된 모델"을 건너뜁니다. 임계값이 너무 높으면 사용 가능한 계정이 과도하게 제외될 수 있습니다.
수정:
- Settings → Quota Protection로 돌아가서 모니터링 모델과 임계값 조정
- 어떤 모델이 보호되었는지 이해하려면 계정 데이터에서
protected_models확인
❌ 오류 3: 고정 계정 모드로 인해 로테이션 불가
현상: Preferred Account를 설정했지만 해당 계정이 속도 제한된 후 시스템이 "멈춥니다".
원인: 고정 계정 모드에서는 시스템이 지정된 계정을 우선 사용하고, 계정을 사용할 수 없을 때만 라운드 로빈으로 강등합니다.
수정:
- 고정 계정이 필요하지 않으면
Preferred Account를 비우세요. - 또는 고정 계정의 할당량이 충분한지 확인하여 속도 제한을 방지하세요.
확인 체크리스트 ✅
- [ ] 할당량 부족과 상류 속도 제한을 구별할 수 있음
- [ ] Proxy Monitor에서 429 오류 세부 정보를 보는 방법을 알고 있음
- [ ] 세 가지 스케줄링 모드의 차이와 사용 시나리오를 이해함
- [ ] 계정 로테이션이 정상 작동하는지 확인하는 방법을 알고 있음
- [ ] 계정 우선순위를 최적화하고 할당량 보호 정책을 확인할 수 있음
자주 묻는 질문
Q1: 여러 계정이 있는데 왜 여전히 429를 만나나요?
A: 가능한 원인:
- 모든 계정이 동시에 속도 제한 트리거(요청 빈도가 너무 높음)
- 연속 요청이 "60초 창 재사" 하에서 계속 동일 계정을 재사용하여 단일 계정을 속도 제한까지 쉽게 끌어올림
- 할당량 보호가 사용 가능한 계정을 잘못 제외함
- 계정 총수가 요청 빈도를 지원하기에 충분하지 않음
해결:
- 더 많은 계정 추가
PerformanceFirst모드 사용- Quota Protection이 사용하려는 모델을
protected_models에 추가했는지 확인(필요시 모니터링 모델과 임계값 조정) - 요청 빈도 낮추기
Q2: 429 오류가 자동으로 재시도되나요?
A: 단일 요청 내에서 자동으로 재시도합니다. 재시시 횟수 상한은 보통 3회이며, 구체적인 계산 방식은 min(3, 계정 풀 크기)이며 최소 1회 시도합니다.
재시시 횟수 예:
- 계정 풀 1개 계정 → 1회 시도(재시도 안 함)
- 계정 풀 2개 계정 → 2회 시도(1회 재시도)
- 계정 풀 3개 이상 계정 → 3회 시도(2회 재시도)
대략적인 흐름:
- 속도 제한/과부하 정보 기록(
RateLimitTracker에 진입) - 대기 시간을 구문 분석할 수 있으면(예:
RetryInfo.retryDelay/quotaResetDelay), 짧은 시간 동안 기다린 후 계속 - 재시시 시 계정 강제 로테이션(
attempt > 0일 때force_rotate=true), 다음 사용 가능한 계정으로 상류 요청 시도
모든 시도가 실패하면 프록시는 오류를 클라이언트에 반환합니다. 동시에 응답 헤더(예: X-Account-Email) 또는 Proxy Monitor에서 실제 사용한 계정을 볼 수 있습니다.
Q3: 특정 계정이 속도 제한된 기간을 어떻게 확인하나요?
A: 두 가지 방법이 있습니다:
방법 1: 로그 확인, rate-limited 검색
🔒 [FIX #820] Preferred account [email protected] is rate-limited, falling back to round-robin방법 2: 로그에 남은 대기 시간 표시
All accounts are currently limited. Please wait 30s.Q4: 할당량 보호와 속도 제한은 같은 것인가요?
A: 아닙니다.
| 특징 | 할당량 보호 | 속도 제한 추적 |
|---|---|---|
| 트리거 조건 | 모델 할당량이 임계값보다 낮음 | 429 오류 수신 |
| 작용 범위 | 특정 모델 | 전체 계정 |
| 지속 시간 | 할당량이 회복될 때까지 | 상류 결정(보통 몇 초에서 몇 분) |
| 동작 | 해당 모델 건너뜀 | 해당 계정 건너뜀 |
Q5: 계정을 즉시 강제 전환하려면 어떻게 하나요?
A: "다음 요청이 더 쉽게 계정을 바꾸도록 만드는" 관점에서 접근할 수 있습니다:
- 스케줄링 측면:
PerformanceFirst로 전환, 스티키 세션 및 60초 창 재사 건너뜀 - 고정 계정:
Preferred Account가 활성화되어 있으면 먼저 비우세요. 그렇지 않으면 고정 계정을 우선 사용함(속도 제한/보호될 때까지) - 계정 풀: 계정 수 증가, 단일 계정이 속도 제한될 때 대체 계정을 더 쉽게 찾기
단일 요청 내에서 프록시 자체도 재시시 시 계정을 강제 로테이션합니다(attempt > 0이면 force_rotate=true 트리거), 하지만 재시시 횟수는 상한 제한을 받습니다.
이 과정 요약
- Antigravity Tools에서 429는 "상류가 일시적으로 사용할 수 없음"을 나타내는 신호이며, 속도 제한, 할당량 고갈, 모델 용량 부족 등 원인일 수 있음
- 프록시는 냉각 시간을 기록하고 단일 요청의 재시시에서 계정 로테이션을 시도(하지만 재시시 횟수는 제한됨)
- 스케줄링 모드, Quota Protection, 계정 수는 429 확률과 복구 속도에 영향을 미침
- Proxy Monitor, 응답 헤더
X-Account-Email및 로그로 빠르게 문제를 찾을 수 있음
다음 과정 예고
다음 과정에서는 **404/경로 호환성 문제: Base URL, /v1 접두사 및 "중첩 경로" 클라이언트**를 학습합니다.
배울 내용:
- 가장 일반적인 연결 오류(404)가 어떻게 발생하는지
- 다른 클라이언트의 base_url 연결 차이
- 404 문제를 빠르게 수정하는 방법
부록: 소스 코드 참조
클릭하여 소스 코드 위치 펼치기
업데이트 시간: 2026-01-23
| 기능 | 파일 경로 | 행 번호 |
|---|---|---|
| 429 재시시 지연 구문 분석(RetryInfo / quotaResetDelay) | src-tauri/src/proxy/upstream/retry.rs | 38-67 |
| Duration 구문 분석 도구 | src-tauri/src/proxy/upstream/retry.rs | 11-35 |
| 스케줄링 모드 열거형(CacheFirst/Balance/PerformanceFirst) | src-tauri/src/proxy/sticky_config.rs | 3-12 |
| 속도 제한 원인 구문 분석 및 기본 냉각 정책 | src-tauri/src/proxy/rate_limit.rs | 5-258 |
| MAX_RETRY_ATTEMPTS 상수 정의(OpenAI handler) | src-tauri/src/proxy/handlers/openai.rs | 14 |
| 재시시 횟수 계산(max_attempts = min(MAX_RETRY_ATTEMPTS, pool_size)) | src-tauri/src/proxy/handlers/openai.rs | 830 |
| OpenAI handler: 429/5xx 시 속도 제한 표시 및 재시도/로테이션 | src-tauri/src/proxy/handlers/openai.rs | 349-389 |
| 계정 정렬 우선순위(ULTRA > PRO > FREE + remaining_quota) | src-tauri/src/proxy/token_manager.rs | 504-538 |
| 60초 창 재사 + 속도 제한/할당량 보호 회피 | src-tauri/src/proxy/token_manager.rs | 624-739 |
| 속도 제한 기록 진입점(mark_rate_limited) | src-tauri/src/proxy/token_manager.rs | 1089-1113 |
| 429 정확한 잠금/실시간 할당량 새로고침/강등 정책(mark_rate_limited_async) | src-tauri/src/proxy/token_manager.rs | 1258-1417 |
핵심 상수:
MAX_RETRY_ATTEMPTS = 3: 단일 요청 내 최대 재시시 횟수(OpenAI/Gemini handler)60: 60초 창 재사(PerformanceFirst외 모드에서만 활성화)5: 토큰 획득 시간 초과(초)300: 토큰 사전 새로고침 임계값(초, 5분)
핵심 함수:
parse_retry_delay(): 429 오류 응답에서 재시시 지연 추출get_token_internal(): 계정 선택과 로테이션의 핵심 로직mark_rate_limited(): 계정을 속도 제한 상태로 표시