Gemini API를 서비스에 붙일 때 가장 먼저 부딪히는 운영 이슈는 모델 품질이 아니라 rate limit입니다. 개발 환경에서는 몇 번 호출해도 잘 되지만, 실제 사용자 트래픽이 들어오면 429 Too Many Requests가 튀어나옵니다. 이때 단순히 “요금제를 올리자”로 해결하면 비용만 늘고 구조적 문제는 그대로 남습니다.
Rate limit 운영의 핵심은 요청을 줄이는 것이 아니라 요청을 예측 가능하게 만드는 것입니다. 어떤 API 호출이 사용자 경험에 즉시 필요하고, 어떤 호출은 큐에 넣어도 되는지 나눠야 합니다. Gemini API는 모델과 사용 단계에 따라 분당 요청 수, 토큰, 일일 제한 같은 기준이 달라질 수 있으므로, 코드에서는 항상 제한이 바뀔 수 있다는 전제로 설계해야 합니다.
많은 팀이 429를 예외 상황으로만 처리합니다. 하지만 AI API에서 429는 시스템이 “지금 속도로 계속 보내면 안 된다”고 알려주는 백프레셔 신호에 가깝습니다. 이 신호를 무시하고 즉시 재시도하면 더 빠르게 막힙니다. 특히 여러 서버 인스턴스가 동시에 같은 API key를 쓰는 구조에서는 각 인스턴스가 “나는 조금만 보냈다”고 생각해도 전체 합산은 제한을 넘을 수 있습니다.
따라서 rate limit 처리는 클라이언트 코드 한 줄의 retry가 아니라 서비스 아키텍처 문제입니다. 요청량을 한곳에서 제어하는 큐, 사용자별 제한, 작업 종류별 우선순위, 실패 시 재시도 간격이 필요합니다. 대화형 답변처럼 사용자가 기다리는 요청과 배치 요약처럼 나중에 처리해도 되는 요청은 같은 줄에 세우면 안 됩니다.
실무 기준으로는 API 호출을 세 등급으로 나누는 것이 좋습니다. 첫째, 사용자 응답에 직접 연결된 synchronous 요청. 둘째, 저장 후 백그라운드에서 처리 가능한 asynchronous 요청. 셋째, 캐시나 사전 계산으로 대체 가능한 요청입니다. 이 분류만 해도 429 대응 전략이 명확해집니다.
429가 발생했을 때 즉시 재호출하는 코드는 가장 먼저 제거해야 합니다. 기본은 exponential backoff입니다. 첫 실패 후 1초, 다음은 2초, 4초처럼 간격을 늘립니다. 여기에 jitter를 넣어야 합니다. 모든 서버가 같은 간격으로 재시도하면 2초 뒤에 다시 트래픽이 몰리는 thundering herd 문제가 생깁니다. 랜덤 지연을 섞어 재시도 시점을 분산해야 합니다.
또한 재시도 횟수에는 상한이 있어야 합니다. 사용자 요청에서 5번, 10번 재시도하면 응답 시간이 망가집니다. 대화형 기능은 1~2회 짧게 재시도하고 실패 메시지를 명확히 보여주는 편이 낫습니다. 백그라운드 작업은 큐에서 지연 재처리할 수 있으므로 더 긴 backoff를 사용할 수 있습니다.
중요한 것은 재시도 가능한 오류와 불가능한 오류를 구분하는 것입니다. 429, 일시적 5xx, 네트워크 timeout은 재시도 후보입니다. 인증 오류, 잘못된 모델명, 요청 포맷 오류는 재시도해도 해결되지 않습니다. 이런 오류까지 큐에 넣으면 비용과 지연만 늘어납니다.
Rate limit은 요청 수만의 문제가 아닙니다. 모델에 보내는 입력 토큰과 출력 토큰도 처리량에 영향을 줍니다. 같은 요청 100건이라도 2,000 토큰짜리 요청과 50,000 토큰짜리 요청은 서버와 비용에 주는 부담이 다릅니다. 따라서 프롬프트 설계는 품질 문제이면서 처리량 문제입니다.
첫 번째 방법은 컨텍스트를 매번 통째로 보내지 않는 것입니다. 대화 기록, 문서, 코드베이스 일부를 매 요청마다 붙이면 토큰이 빠르게 늘어납니다. 필요한 범위를 검색하거나 요약한 뒤 보내야 합니다. 두 번째는 출력 형식을 제한하는 것입니다. “자세히 설명해줘”보다 “JSON 배열 5개, 각 항목 2문장”처럼 길이와 구조를 지정하면 출력 토큰을 제어할 수 있습니다.
세 번째는 중복 요청을 제거하는 것입니다. 같은 문서 요약, 같은 상품 설명 생성, 같은 코드 분석은 캐시할 수 있습니다. 사용자가 버튼을 두 번 누르거나 네트워크 재시도로 같은 작업이 중복 실행되는 경우도 많습니다. idempotency key를 두면 같은 요청이 여러 번 들어와도 한 번만 처리할 수 있습니다.
Gemini API를 제품 기능에 넣는다면 큐는 선택이 아닙니다. 모든 요청을 웹 서버에서 바로 외부 API로 보내면 트래픽 피크를 흡수할 수 없습니다. 큐를 두면 요청을 일정 속도로 배출하고, 실패 작업을 재처리하고, 중요 작업을 먼저 처리할 수 있습니다.
우선순위는 사용자 경험 기준으로 정합니다. 사용자가 화면에서 기다리는 응답은 높은 우선순위입니다. 알림 문구 개선, 백오피스 분류, 일괄 요약은 낮은 우선순위입니다. 낮은 우선순위 작업은 rate limit이 빡빡할 때 자동으로 지연시켜도 됩니다. 이렇게 해야 핵심 사용자 흐름이 배치 작업 때문에 막히지 않습니다.
큐에는 timeout과 dead letter queue가 필요합니다. 일정 횟수 이상 실패한 작업은 계속 재시도하지 말고 별도 저장소로 보내 원인을 확인해야 합니다. 특히 프롬프트 포맷 오류나 입력 데이터 문제는 재시도로 해결되지 않습니다. 실패 원인을 로그로 남기지 않으면 운영자는 “Gemini가 불안정하다”고만 느끼고 실제 버그를 찾지 못합니다.
AI API 운영 지표는 단순 성공률만으로 부족합니다. 최소한 요청 수, 입력 토큰, 출력 토큰, 429 비율, 평균 지연 시간, p95 지연 시간, 재시도 횟수, 큐 대기 시간을 봐야 합니다. 사용자별 또는 기능별로 나눠 보면 어떤 기능이 제한을 많이 쓰는지 알 수 있습니다.
비용 지표도 함께 봐야 합니다. rate limit 문제는 비용 문제와 연결됩니다. 긴 프롬프트를 줄이면 처리량이 좋아지고 비용도 내려갑니다. 캐시 적중률이 올라가면 429도 줄고 응답 속도도 빨라집니다. 따라서 대시보드는 기술 지표와 비용 지표를 분리하지 말고 같은 화면에서 보는 편이 좋습니다.
알림 기준은 보수적으로 잡으세요. 429가 0.1%만 발생해도 사용자가 체감할 수 있는 기능이라면 알림 대상입니다. 반대로 백그라운드 작업에서 짧은 피크가 나는 것은 큐가 잘 흡수한다면 큰 문제가 아닐 수 있습니다. 기능의 중요도에 따라 SLO를 다르게 두는 것이 현실적입니다.
Gemini API의 rate limit은 피해야 할 벽이 아니라 서비스가 안정적으로 동작하도록 알려주는 속도계입니다. 이 신호를 코드와 큐 설계에 반영하면 같은 요금제에서도 더 많은 요청을 안정적으로 처리할 수 있습니다.