Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions docs/RATE_LIMITER_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
# Rate Limiter 설정 가이드

## 📊 기본 설정 (2025.09.21 기준)
## 📊 기본 설정 (v1.7.x 기준)

PyKIS의 Rate Limiter는 실제 테스트를 바탕으로 안정성을 우선시하여 설정되었습니다.
kis-agent의 Rate Limiter는 KIS 공식 한도(20 RPS / 1000 RPM) 대비 충분한 안전
마진을 두고, 동시 호출 시에도 sliding window 위반이 발생하지 않도록 설계되어
있습니다.

### 기본값
```python
# pykis/core/rate_limiter.py 기본 설정
# kis_agent/core/rate_limiter.py의 DEFAULT_* 상수
{
'requests_per_second': 18, # API 스펙: 20 (안정성을 위해 90% 수준)
'requests_per_minute': 900, # API 스펙: 1000 (안정성을 위해 90% 수준)
'min_interval_ms': 50, # API 권장: 50ms
'burst_size': 10, # 순간 버스트 허용량
'enable_adaptive': True # 적응형 백오프 활성화
'requests_per_second': 15, # 공식 한도 20의 75% (5회 여유)
'requests_per_minute': 800, # 공식 한도 1000의 80% (200회 여유)
'min_interval_ms': 70, # 15 RPS의 이론적 67ms + 3ms jitter
'burst_size': 3, # priority>=1 시 effective RPS = 18
'enable_adaptive': True # 적응형 백오프 활성화
}
```

### 안전 보장

- **공식 한도 자동 클램프**: `RateLimiter(requests_per_second=25)`처럼 공식 한도를
초과하는 값을 주면 자동으로 20으로 clamp됩니다 (RPM도 동일).
- **동시 호출 안전**: 다수의 스레드가 동시에 acquire()를 호출해도 sliding window
내 요청 수가 한도를 넘지 않습니다 (1ms safety padding + slot reservation).
- **Lock-free sleep**: `acquire()`의 `time.sleep()`이 lock 바깥에서 실행되어 한
스레드의 대기가 다른 스레드를 블록하지 않습니다.
- **전역 싱글턴**: 모든 KISClient/Agent가 동일한 RateLimiter 인스턴스를 공유합니다.

## 🎯 사용 시나리오별 권장 설정

### 1. 안정성 최우선 (Production)
Expand Down
25 changes: 7 additions & 18 deletions kis_agent/core/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,28 +177,17 @@ def __init__(
)

# Rate Limiter 설정 (전역 싱글턴 패턴)
# 모든 Agent와 KISClient가 동일한 Rate Limiter 인스턴스를 공유하여
# API 호출 제한을 전역적으로 관리합니다.
# 기본값은 kis_agent.core.rate_limiter의 DEFAULT_* 상수를 사용한다
# (공식 20 RPS / 1000 RPM 대비 75% / 80% 안전 마진).
# 사용자가 rate_limiter_config로 일부 키를 override할 수 있다.
if enable_rate_limiter:
if rate_limiter:
# 명시적으로 전달된 rate_limiter 사용 (테스트 등 특수 목적)
self.rate_limiter = rate_limiter
elif rate_limiter_config:
# 사용자 override는 첫 호출에서만 적용됨 (싱글턴이므로)
self.rate_limiter = get_global_rate_limiter(**rate_limiter_config)
else:
# 전역 싱글턴 Rate Limiter 사용 (2025.09.21 실측 기반)
# 공식 스펙: 초당 20회 / 분당 1000회
# 안정 운영: 초당 18회 / 분당 900회 (실측 기반 권장)
default_config = {
"requests_per_second": 18, # 실측 기반 안정 한계
"requests_per_minute": 900, # 실측 기반 안정 한계
"min_interval_ms": 55, # 최소 55ms 간격 (18 RPS 기준)
"burst_size": 10, # 순간 처리량 허용
"enable_adaptive": True,
}
if rate_limiter_config:
default_config.update(rate_limiter_config)

# 전역 싱글턴 Rate Limiter 획득
self.rate_limiter = get_global_rate_limiter(**default_config)
self.rate_limiter = get_global_rate_limiter()
else:
self.rate_limiter = None

Expand Down
17 changes: 5 additions & 12 deletions kis_agent/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,13 @@ def __init__(
self.rate_limit_lock = threading.Lock() # 인스턴스별 rate limit lock
self.token_refresh_lock = threading.Lock() # 토큰 재생성 동기화용 락

# Rate Limiter 설정 (2025.09.21 실측 기반)
# 공식 스펙: 초당 20회 / 분당 1000회
# 안정 운영: 초당 18회 / 분당 900회 (실측 기반 권장)
# 전역 싱글턴 사용: 모든 KISClient/Agent가 동일한 Rate Limiter 공유
# Rate Limiter 설정 — 기본값은 kis_agent.core.rate_limiter의 DEFAULT_*
# (공식 스펙 20 RPS / 1000 RPM 대비 75% / 80% 안전 마진).
# 전역 싱글턴 사용: 모든 KISClient/Agent가 동일한 Rate Limiter 공유.
# 명시적으로 전달된 rate_limiter가 있으면 그것을 사용 (테스트 등 특수 목적).
self.enable_rate_limiter = enable_rate_limiter
if enable_rate_limiter:
# 명시적으로 전달된 rate_limiter가 있으면 사용, 없으면 전역 싱글턴 사용
self.rate_limiter = rate_limiter or get_global_rate_limiter(
requests_per_second=18, # 실측 기반 안정 한계
requests_per_minute=900, # 실측 기반 안정 한계
min_interval_ms=55, # 최소 55ms 간격 (18 RPS 기준)
burst_size=10, # 순간 처리량 허용
enable_adaptive=True,
)
self.rate_limiter = rate_limiter or get_global_rate_limiter()
else:
self.rate_limiter = None

Expand Down
Loading
Loading