API 사용량 상한과 비용 알림을 붙인 기록
개인 프로젝트는 처음에 사용자가 적어 비용도 작습니다. 그래서 사용량 제한을 나중에 붙이려 합니다. 하지만 공개 주소가 알려지거나 자동화된 요청이 들어오면 비용과 장애가 동시에 커질 수 있습니다.
저는 기능을 추가하기 전에 요청을 세고, 상한을 넘으면 알려 주고, 더 넘으면 안전하게 거절하는 흐름을 만들기로 했습니다. 이번 글에서는 숫자 자체보다 제한 정책을 정하는 순서를 설명합니다.
API마다 비용과 위험이 다릅니다
모든 엔드포인트에 같은 제한을 걸면 사용자는 불편하고 운영자는 중요한 기능을 구분하지 못합니다. 읽기 요청은 캐시로 흡수할 수 있지만, 외부 AI 호출이나 파일 변환은 한 번의 요청도 비용이 큽니다.
저는 먼저 엔드포인트를 비용·시간·데이터 변경 여부로 나눕니다. 그 다음 사용자별 제한과 전체 제한 중 무엇이 필요한지 결정합니다.
유형주요 위험먼저 볼 지표
| 읽기 | 트래픽·캐시 미스 | 요청 수·캐시 적중률 |
| 쓰기 | 중복 데이터·스팸 | 사용자별 요청 수 |
| 외부 API | 호출 비용·쿼터 | 공급자 사용량·실패율 |
| 파일 작업 | CPU·스토리지 | 처리 시간·파일 크기 |
상한·경고·차단을 세 단계로 둡니다
상한 하나만 정하면 갑자기 모든 요청을 막거나 비용이 이미 커진 뒤에 알게 됩니다. 저는 경고 임계값, 소프트 제한, 하드 제한을 나눕니다. 경고는 운영자에게 알리고, 소프트 제한은 사용자에게 속도를 늦추며, 하드 제한은 새로운 처리를 거절합니다.
제한에 걸렸을 때는 내부 오류를 그대로 보여 주지 않고 재시도 시각과 문의 방법을 안내합니다. 실패 응답도 제품 경험의 일부이기 때문입니다.
- 경고: 평소 사용량을 벗어나기 시작했다는 알림입니다.
- 소프트 제한: 일부 기능을 늦추거나 대기열에 넣는 단계입니다.
- 하드 제한: 추가 비용을 막기 위해 요청을 명확히 거절하는 단계입니다.
ASP.NET Core Rate Limiting을 정책으로 읽습니다
ASP.NET Core의 Rate Limiting은 고정 창, 슬라이딩 창, 토큰 버킷, 동시성 제한처럼 목적이 다른 알고리즘을 제공합니다. 중요한 것은 코드를 복사하는 것이 아니라 엔드포인트의 비용과 사용자 경험에 맞게 정책을 연결하는 것입니다.
예를 들어 일정한 분당 호출량은 고정 창으로 시작할 수 있지만, 짧은 시간에 몰리는 작업은 토큰 버킷이나 동시성 제한이 더 맞을 수 있습니다. 어떤 값을 택했는지와 부하 테스트 결과를 함께 기록해야 합니다.
- 고정 창: 시간 구간마다 허용량을 다시 채우는 단순한 정책입니다.
- 슬라이딩 창: 경계 시점에 요청이 몰리는 현상을 줄이는 데 유리합니다.
- 토큰 버킷: 평소 요청과 짧은 순간의 버스트를 함께 다룹니다.
- 동시성: 시간당 수보다 동시에 실행되는 작업 수를 제한합니다.
비용 알림은 대시보드보다 행동과 연결해야 합니다
알림이 오기만 하고 누가 무엇을 할지 정해져 있지 않으면 실제 대응은 늦어집니다. 저는 알림마다 담당 행동을 붙입니다. 예를 들어 외부 API 사용량이 경고선을 넘으면 신규 기능을 잠시 막고, 로그 샘플링을 높이고, 공급자 대시보드를 확인합니다.
무료 한도와 가격은 바뀔 수 있으므로 문서에 조사일을 기록합니다. 비용을 정확히 예측하는 것보다 상한을 넘었을 때 더 커지지 않게 만드는 것이 1인 프로젝트에는 현실적인 목표입니다.
운영 가능한 크기로 줄이는 순서
작은 도구나 서비스의 설계는 기능 목록을 늘리는 일보다 경계를 줄이는 일에 가깝습니다. 저는 먼저 입력과 출력, 실패했을 때 사용자가 되돌릴 수 있는 지점을 적습니다. 그 다음 실제 사용량이나 파일 한두 개로 기준선을 만들고, 가장 비싼 작업과 가장 위험한 작업을 따로 표시합니다. 이 과정을 거치면 ‘있으면 좋은 기능’과 ‘없으면 복구할 수 없는 기능’을 구분할 수 있습니다.
첫 버전은 관찰할 수 있어야 합니다. 요청 수·처리 시간·오류·복구 성공 여부처럼 다음 결정을 돕는 기록을 최소한으로 남깁니다. 자동화나 클라우드 기능을 붙일 때도 기본값과 상한을 먼저 정하고, 테스트용 자원과 운영 자원을 분리합니다. 실패했을 때 원상 복구할 수 없는 기능은 공개 범위를 좁혀 시작하는 편이 안전합니다.
- 경계: 지원하는 입력·사용자·환경과 지원하지 않는 범위를 적습니다.
- 기준선: 정상 입력 하나와 실패 입력 하나를 저장해 반복 테스트합니다.
- 관찰: 비용·지연·오류·복구에 필요한 최소 지표만 수집합니다.
- 되돌리기: 배포·삭제·마이그레이션을 취소하는 절차를 실제로 시험합니다.
다음 작업에서 다시 확인할 항목
한 번 적용한 방법이 언제나 같은 결과를 내는 것은 아닙니다. 사람과 서비스와 원고의 조건이 바뀌면 같은 원칙도 다른 판단을 요구합니다. 그래서 저는 글을 작성한 뒤 결론만 보관하지 않고, 결론이 성립한 조건과 다시 확인해야 할 조건을 함께 적습니다. 이 기록이 있으면 몇 달 뒤 글을 업데이트할 때 당시의 경험을 현재의 사실처럼 착각하지 않을 수 있습니다.
특히 버전·정책·가격·플랫폼 기능처럼 외부에서 바뀌는 내용은 조사한 날짜와 공식 문서의 주소를 남깁니다. 발행 시점에 문서가 달라졌다면 본문에 변경 사실을 표시하고, 직접 확인하지 못한 부분은 독자가 알 수 있도록 범위를 제한합니다. 경험을 공유하는 글도 다른 사람의 환경에 그대로 적용될 수 있으므로, 성공 사례보다 실패 조건을 함께 쓰는 편이 안전합니다.
마지막으로 이 글을 읽은 분이 바로 할 수 있는 행동은 하나로 줄입니다. 모든 항목을 한꺼번에 바꾸기보다 현재 상태를 기록하고, 작은 실험을 한 번 실행하고, 결과를 다시 적는 순서입니다. 그렇게 쌓인 기록이 다음 글의 소재가 되고, 처음의 판단을 더 정확하게 고쳐 쓰는 근거가 됩니다.
- 범위 표시: 이 글의 결론이 적용되는 환경과 적용되지 않는 환경을 구분합니다.
- 날짜 기록: 버전·정책·가격·문서를 확인한 날짜를 남깁니다.
- 실패 조건: 어떤 상황에서는 이 방법을 쓰지 말아야 하는지 적습니다.
- 작은 실행: 독자가 오늘 시도할 수 있는 가장 작은 행동을 고릅니다.
- 후속 기록: 실행 결과와 다음에 바꿀 조건을 별도 메모로 남깁니다.
이 기록을 나중에 다시 읽을 때는 결과만 보지 않고 당시의 조건도 함께 확인합니다. 조건이 달라졌다면 결론을 그대로 복사하지 말고 현재의 입력과 제약을 다시 적습니다. 그 과정을 거쳐야 이 글이 단순한 경험담이 아니라 다음 판단을 돕는 작업 기록으로 남습니다.
마치며
사용량 제한은 사용자를 막기 위한 장치가 아니라 혼자 운영하는 서비스가 감당할 수 있는 범위를 알려 주는 안전장치입니다. 가장 비용이 큰 API 하나를 골라 경고·소프트 제한·하드 제한 세 단계를 먼저 설계해 보시기 바랍니다.
참고한 문서: ASP.NET Core Rate Limiting · Cloudflare Workers AI 가격