증권 API 레이트리밋과 재시도 설계 — 요청이 몰릴 때 계좌를 지키는 법
장 시작 직후 요청이 몰리면 벌어지는 일
장이 열리는 순간, 여러 종목을 동시에 조회하거나 여러 주문을 한꺼번에 넣으려는 코드는 짧은 시간에 API 요청이 몰리게 된다. 증권사 API는 대부분 초당·분당 요청 한도(레이트리밋)를 두고 있어서, 이 한도를 넘으면 요청이 거부되거나 일시 차단된다. 에러코드 핸들링에서 다룬 "일시적 에러" 그룹 중 상당수가 사실 이 레이트리밋 문제다.
이 글은 특정 증권사의 실제 요청 한도 수치를 다루지 않는다. 대신 한도가 얼마든 적용할 수 있는 재시도·백오프 설계를 다룬다.
무작정 재시도하면 안 되는 이유
레이트리밋에 걸렸는데 곧바로 다시 요청을 보내면, 한도가 풀리기 전에 또 걸린다. 더 나쁜 경우 이런 재시도가 쌓이면 요청 폭주 자체가 다음 한도 초과의 원인이 된다.
지수 백오프(Exponential Backoff)로 재시도 간격을 늘린다
python 코드 보기
def call_with_backoff(request_fn, max_retries=5, base_delay=1.0):
for attempt in range(max_retries):
response = request_fn()
if response.is_success:
return response
if response.error_type != "rate_limited":
raise ApiError(response.error_code)
delay = base_delay * (2 ** attempt) + random_uniform(0, base_delay)
sleep(delay)
raise ApiError("재시도 한도 초과 - 요청 중단")여기서 중요한 건 재시도할 때마다 대기 시간을 두 배씩 늘린다는 점이다. 이렇게 하면 한도가 실제로 풀릴 시간을 벌어주면서, 그 사이에도 계속 요청을 쏘는 상황을 막는다. delay 계산에 더한 무작위 지터(jitter)도 같은 이유다 — 같은 한도 초과를 겪은 여러 종목·여러 프로세스의 재시도가 정확히 같은 간격으로 동시에 몰리면, 두 배씩 늘려도 한 박자마다 다시 요청이 겹쳐 한도를 또 넘긴다. 대기 시간에 약간의 무작위성을 섞어 재시도 타이밍을 흩어놓는 것도 백오프 설계의 일부다.
애초에 요청을 몰리지 않게 만드는 큐 설계
재시도만으로는 부족하다. 여러 종목을 조회해야 할 때 한 번에 다 쏘지 않고, 요청을 큐에 넣고 정해진 속도로만 꺼내 보내는 방식이 근본적인 해법이다. 초당 처리 가능한 요청 수를 알고 있다면, 그 속도에 맞춰 큐에서 요청을 하나씩 꺼내는 구조를 만들면 애초에 레이트리밋에 걸릴 일이 줄어든다.
자주 하는 실수
- 재시도 간격을 고정값으로 둔다. 한도가 안 풀렸는데 같은 간격으로 계속 재시도해 오히려 상황을 악화시킨다.
- 재시도 횟수에 상한을 두지 않는다. 근본 원인이 해결되지 않는 상황에서 무한 재시도는 무인 운영에서 다룬 "조용히 멈춘 것처럼 보이는" 상태를 만든다.
- 레이트리밋 에러와 다른 종류의 에러를 같은 재시도 로직으로 처리한다. 인증 오류처럼 재시도로 해결되지 않는 에러까지 백오프에 태우면 문제 발견이 늦어진다.
오늘의 정리
- 증권사 API는 대부분 요청 한도를 두므로, 요청이 몰리는 장 시작 직후 등에는 레이트리밋에 걸릴 가능성을 항상 염두에 둬야 한다.
- 레이트리밋에 걸렸을 때 곧바로 재시도하면 상황이 악화되므로, 재시도 간격을 점점 늘리는 지수 백오프가 안전하다.
- 재시도만으로 해결하려 하지 말고, 요청 자체를 큐에 넣어 속도를 조절하는 설계가 근본적인 해법이다.
- 레이트리밋 에러와 다른 종류의 에러는 분리해서 처리해야, 재시도로 해결되지 않는 문제를 조기에 발견할 수 있다.
이 글의 코드는 재시도 설계를 설명하기 위한 의사코드이며 특정 증권사의 실제 요청 한도나 API 응답을 담고 있지 않습니다. 실제 연동은 반드시 해당 증권사 공식 API 문서를 기준으로 진행하시기 바랍니다. 이 글은 투자 조언이 아니며 특정 종목이나 매매기법을 추천하지 않습니다. 수익을 보장하지 않으며, 투자 손실에 대한 책임은 투자자 본인에게 있습니다.