API에 제한을 붙일 때 가장 먼저 떠오르는 문장은 ‘분당 몇 번 허용할까’입니다. 하지만 같은 분당 열 번이라도 읽기 요청과 파일 변환 요청의 비용은 다릅니다. 제한값 하나를 정하기 전에 정책의 목적을 분리해야 합니다.
이번 글에서는 ASP.NET Core의 Rate Limiting 미들웨어를 특정 값의 정답이 아니라 정책 선택 도구로 읽어 보겠습니다. 실제 값은 부하 테스트와 사용자 행동을 보고 조정해야 합니다.
제한의 목적을 네 가지로 나눕니다
Rate Limiting은 악성 요청만 막는 기능이 아닙니다. 공정 사용량을 보장하고, 백엔드 자원을 보호하고, 외부 비용을 통제하고, 동시 작업 수를 제한하는 데 사용할 수 있습니다. 목적이 다르면 관찰할 지표와 실패 응답도 달라집니다.
저는 엔드포인트마다 ‘무엇을 보호하는가’를 한 줄로 적습니다. 목적이 없으면 제한을 완화하거나 강화할 때 기준을 잃습니다.
- 남용 방지: 특정 클라이언트가 자원을 독점하지 않게 합니다.
- 공정 사용: 사용자별 또는 요금제별 기회를 나눕니다.
- 자원 보호: CPU·DB·외부 API가 감당할 수 있는 속도를 지킵니다.
- 비용 관리: 호출량에 따라 요금이 늘어나는 작업을 통제합니다.
알고리즘은 요청의 모양으로 선택합니다
고정 창은 구현과 설명이 쉽지만 경계 시점에 요청이 몰릴 수 있습니다. 슬라이딩 창은 이 현상을 완화하고, 토큰 버킷은 평소 허용량과 짧은 버스트를 함께 다룹니다. 동시성 제한은 시간당 요청보다 동시에 실행되는 작업의 수가 중요한 경우에 맞습니다.
알고리즘 이름보다 요청의 모양을 먼저 그려 보는 것이 좋습니다. 사용자가 버튼을 연속으로 누르는지, 긴 작업이 병렬로 실행되는지, 일정한 간격으로 조회하는지에 따라 선택이 달라집니다.
알고리즘잘 맞는 상황주의할 점
| 고정 창 | 단순한 분당 호출량 | 경계 시점 몰림 |
| 슬라이딩 창 | 균일한 속도 관리 | 상태 계산 비용 |
| 토큰 버킷 | 짧은 버스트 허용 | 버킷 크기 해석 |
| 동시성 | 긴 작업·파일 처리 | 완료 전 자원 점유 |
정책은 전역보다 경로에 가깝게 적용합니다
모든 API에 같은 전역 제한을 적용하면 내부 관리 요청과 공개 요청이 충돌할 수 있습니다. 공개 검색, 로그인, 파일 처리, 관리자 경로를 나눠 정책을 부착하는 편이 조정하기 쉽습니다.
ASP.NET Core에서 엔드포인트별 정책을 사용할 때는 라우팅과 미들웨어 순서를 확인해야 합니다. 코드가 동작하더라도 정책이 적용되지 않은 경로가 없는지 테스트로 확인합니다.
- 공개 읽기: 캐시와 함께 사용하고 비교적 넓게 설정합니다.
- 쓰기: 사용자·IP·멱등 키를 조합해 중복을 줄입니다.
- 긴 작업: 동시성 제한과 작업 상태 조회를 함께 둡니다.
- 관리자: 인증과 별도의 높은 제한을 사용합니다.
부하 테스트와 사용자 메시지가 정책을 완성합니다
제한값은 코드 리뷰만으로 정할 수 없습니다. 정상 사용 시나리오와 반복 요청 시나리오를 나눠 테스트하고, 정상 사용자가 제한에 걸리는 비율을 확인합니다. 429 응답이 나왔을 때 재시도 시각과 요청 식별자를 보여 주면 지원 문의도 줄어듭니다.
운영 후에는 제한에 걸린 횟수, 경로, 정책, 정상 복구 여부를 기록합니다. 값이 너무 낮아 불편한지, 너무 높아 자원을 보호하지 못하는지 실제 기록으로 조정합니다.
실험 결과를 운영 판단으로 바꾸는 순서
개발 문서에서 가장 재사용하기 어려운 문장은 ‘잘 됩니다’입니다. 어떤 버전과 데이터, 부하에서 잘 되었는지 모르면 독자는 자신의 환경에서 다시 확인할 수 없습니다. 저는 새로운 기능을 검토할 때 SDK·런타임·패키지·데이터베이스 버전을 먼저 고정하고, 기존 구현을 기준선으로 보관합니다. 변경 전후의 코드와 측정 명령도 함께 기록합니다.
측정값이 좋아도 운영에 바로 도입하지 않습니다. 오류 추적, 로그의 의미, 배포와 롤백, 팀이 이해할 수 있는지까지 확인합니다. 프리뷰나 변경 중인 문서는 정식 기능과 구분하고, 문서에 확인 날짜와 테스트 범위를 적습니다. 독자가 복사해 사용해도 위험하지 않도록 적용하지 말아야 하는 조건도 함께 적는 것이 기술 글의 중요한 부분입니다.
- 버전 잠금: 실험한 SDK·런타임·패키지·브라우저 버전을 기록합니다.
- 기준선: 변경 전 기능·성능·오류 결과를 같은 입력으로 보관합니다.
- 경계 사례: 빈 값·중복·실패·큰 입력에서 결과를 확인합니다.
- 배포 판단: 적용·보류·롤백 중 하나를 고르고 근거를 남깁니다.
다음 작업에서 다시 확인할 항목
한 번 적용한 방법이 언제나 같은 결과를 내는 것은 아닙니다. 사람과 서비스와 원고의 조건이 바뀌면 같은 원칙도 다른 판단을 요구합니다. 그래서 저는 글을 작성한 뒤 결론만 보관하지 않고, 결론이 성립한 조건과 다시 확인해야 할 조건을 함께 적습니다. 이 기록이 있으면 몇 달 뒤 글을 업데이트할 때 당시의 경험을 현재의 사실처럼 착각하지 않을 수 있습니다.
특히 버전·정책·가격·플랫폼 기능처럼 외부에서 바뀌는 내용은 조사한 날짜와 공식 문서의 주소를 남깁니다. 발행 시점에 문서가 달라졌다면 본문에 변경 사실을 표시하고, 직접 확인하지 못한 부분은 독자가 알 수 있도록 범위를 제한합니다. 경험을 공유하는 글도 다른 사람의 환경에 그대로 적용될 수 있으므로, 성공 사례보다 실패 조건을 함께 쓰는 편이 안전합니다.
마지막으로 이 글을 읽은 분이 바로 할 수 있는 행동은 하나로 줄입니다. 모든 항목을 한꺼번에 바꾸기보다 현재 상태를 기록하고, 작은 실험을 한 번 실행하고, 결과를 다시 적는 순서입니다. 그렇게 쌓인 기록이 다음 글의 소재가 되고, 처음의 판단을 더 정확하게 고쳐 쓰는 근거가 됩니다.
- 범위 표시: 이 글의 결론이 적용되는 환경과 적용되지 않는 환경을 구분합니다.
- 날짜 기록: 버전·정책·가격·문서를 확인한 날짜를 남깁니다.
- 실패 조건: 어떤 상황에서는 이 방법을 쓰지 말아야 하는지 적습니다.
- 작은 실행: 독자가 오늘 시도할 수 있는 가장 작은 행동을 고릅니다.
- 후속 기록: 실행 결과와 다음에 바꿀 조건을 별도 메모로 남깁니다.
이 기록을 나중에 다시 읽을 때는 결과만 보지 않고 당시의 조건도 함께 확인합니다. 조건이 달라졌다면 결론을 그대로 복사하지 말고 현재의 입력과 제약을 다시 적습니다. 그 과정을 거쳐야 이 글이 단순한 경험담이 아니라 다음 판단을 돕는 작업 기록으로 남습니다.
마치며
Rate Limiting의 핵심은 숫자를 작게 만드는 것이 아니라 API의 비용과 사용 기회를 예측 가능하게 만드는 것입니다. 가장 중요한 엔드포인트 하나를 골라 보호 대상·알고리즘·실패 응답·부하 테스트를 한 장에 정리해 보시기 바랍니다.
참고한 문서: ASP.NET Core Rate Limiting · Cloudflare Rate Limiting
'개발 노트 > ASP.NET Core' 카테고리의 다른 글
| .NET 11 Runtime Async를 기존 async/await와 비교해 본 체크리스트 (0) | 2026.09.28 |
|---|---|
| Kestrel 개선과 Zstandard 압축 — 응답 크기와 CPU를 같이 줄이기 (1) | 2026.09.05 |
| Minimal API 비동기 검증과 OpenAPI 3.2 — .NET 11에서 달라지는 것 (0) | 2026.09.04 |
| .NET 11 정식 출시 전 점검 — 실서비스 마이그레이션 체크리스트 (0) | 2026.09.03 |
| 닷넷 11 프리뷰에서 지켜볼 만한 것들 (0) | 2026.07.09 |