~/csslab.dev/notes $ ls

// note

LLM 호출 한도 — 인스턴스별 카운터로는 못 막음

  • 여러 사용자가 동시에 쓰는 LLM 어시스턴트 서비스의 백엔드

증상

  • 사용자가 몰리면 LLM 공급자 한도(분당 요청 수·분당 토큰 수)에 걸려 호출이 실패
  • 서버 각각은 여유가 있다고 판단하는데도 발생

원인

  • 한도 카운터가 프로세스 메모리에 있음 — 인스턴스가 3대면 각자 전체의 1/3만 보고 "여유 있음"으로 판정 → 합치면 초과
  • 여유를 확인하는 시점과 사용량을 기록하는 시점이 벌어져, 그 사이에 도착한 요청이 같은 여유를 다시 읽고 통과

조치

  • 한도 상태를 Redis로 이동 — 인스턴스가 몇 대든 한 곳에서 셈. 슬라이딩 윈도로 최근 1분치만 남기고 지나간 기록은 버림
  • 확인과 기록을 Lua 스크립트로 묶어 Redis 안에서 한 번에 실행 — 네트워크 왕복 사이에 다른 요청이 끼어들 틈을 없앰
  • 초과분은 거부 대신 대기열 — sorted set에 도착 시각을 score로 넣어 FIFO 유지. 순위를 조회해 대기 순번을 WebSocket으로 통지
  • 대기열 소진은 이벤트 구독으로 — 큐 키의 변경 알림을 구독해 워커가 즉시 깨어나고, 알림 유실에 대비해 주기적 폴링을 폴백으로 병행
  • 사용량은 선차감 후 정산 — LLM 출력 길이를 미리 알 수 없어 최대치로 자리를 잡아둔 뒤, 응답이 끝나면 실측으로 보정

결과

  • 한도 초과가 실패가 아니라 대기로 바뀌어 사용자 재시도가 사라짐
  • 인스턴스를 늘려도 전역 한도가 유지됨

순번·정산 결과를 사용자 소켓으로 되돌리는 쪽 → 수평 확장 WebSocket 세션 라우팅