BTP API Management Rate Limit 모르면 큰일 #shorts #SAP #BTP
1. 왜 Rate Limit을 반드시 설정해야 하는가?
API를 외부에 공개했는데 Rate Limit을 걸지 않으면 어떤 일이 벌어질까요? 실제 현장에서 가장 많이 발생하는 장애 패턴 세 가지를 먼저 짚고 갑니다. 이 설정을 안 하면 정말로 새벽에 호출받습니다.
- 백엔드 폭사 — 클라이언트의 무한루프 버그 한 줄 때문에 초당 수천 건이 ERP/HANA Cloud로 직격당해 DB 커넥션 풀이 마름
- 비용 폭증 — Generative AI Hub나 외부 SaaS 호출이 API Management를 거치는 경우, 토큰 단가 x 호출량으로 월 청구서가 자릿수가 바뀜
- 의도된 DDoS — 인증은 통과한 정상 토큰으로 들어오는 트래픽이라 XSUAA로는 못 막음. 정책 레이어에서 차단해야 함
SAP BTP API Management(Apigee Edge 기반)는 Policy 단계에서 트래픽을 1차로 차단하므로 백엔드 비즈니스 로직보다 훨씬 가볍게 거절합니다. 일반적으로 백엔드 보호의 첫 번째 방어선으로 권장됩니다.
학습 체크리스트입니다.
- Rate Limit / Quota / Spike Arrest 세 정책의 차이를 1분 안에 설명할 수 있다
- XML로 직접 정책을 작성하고 PreFlow에 붙일 수 있다
- 429 응답을 커스텀 JSON으로 내려줄 수 있다
- Spike Arrest와 Quota를 조합한 다단계 방어 전략을 설계할 수 있다
2. SAP BTP API Management 3대 트래픽 정책 비교
세 가지 정책이 비슷해 보이지만 적용 목적이 완전히 다릅니다. 한 줄 비유부터 잡고 가겠습니다.
| 정책 | 비유 | 측정 단위 | 주 목적 |
|---|---|---|---|
| Spike Arrest | 고속도로 톨게이트 차단봉 | 초/분 (smoothing) | 순간 폭주 방어 |
| Rate Limit | 분당 입장 카운터 | 분/시간 (윈도우) | 처리량 평탄화 |
| Quota | 월 정액 요금제 | 일/주/월 | 비즈니스 라이선스 |
Spike Arrest는 "Rate 100ps"로 설정해도 100건을 1초 안에 받지 않습니다. 10ms 간격으로 균등 분산되어 들어와야 통과시킵니다. 즉 burst 자체를 거부하는 정책입니다. 반면 Rate Limit은 "1분에 1000건까지 OK, 1초 안에 다 들어와도 OK"라는 윈도우 카운팅 방식입니다. Quota는 개발자(API Key) 단위로 "이 앱은 하루 10000건"처럼 비즈니스 SLA를 강제할 때 씁니다.
실무 결론을 먼저 말씀드리면, 외부 공개 API에는 보통 Spike Arrest + Quota 조합을 PreFlow에 둡니다. Rate Limit은 두 정책 사이의 미세 조정 또는 내부 백엔드 보호용으로 사용하는 경우가 많습니다.
3. Rate Limit 정책 XML 설정 실전
API Management 콘솔의 API Proxy → Policies → Create Policy → "Rate Limit" 선택 후 다음 XML을 붙여넣습니다. PreFlow Request 단계에 attach 하는 것이 표준입니다.
<!-- 분당 1000건, 클라이언트 IP 기준 -->
<RateLimit async="false" continueOnError="false" enabled="true" type="HierarchicalRateLimit" xmlns="http://www.sap.com/apimgmt">
<DisplayName>RL-PerClientIP-1000pm</DisplayName>
<Identifier ref="client.ip" />
<MessageWeight ref="request.header.weight" />
<Rate>
<Allow count="1000" />
<Interval ref="request.header.interval">1</Interval>
<TimeUnit ref="request.header.timeunit">minute</TimeUnit>
</Rate>
</RateLimit>
핵심 속성을 짚어보면, Identifier는 카운팅 키입니다. client.ip 대신 verifyapikey.{policyName}.client_id나 request.header.X-Consumer-Id를 쓰면 앱 단위로 카운트됩니다. MessageWeight는 한 요청을 N건으로 셀 때 씁니다(예: 무거운 검색 API는 weight=5).
continueOnError="false"로 두면 한도 초과 시 즉시 거절합니다. 응답 헤더에 X-RateLimit-Remaining이 자동으로 실리므로 클라이언트가 백오프 로직을 짤 수 있습니다.
4. Quota 정책 설정 — 일/월 단위 호출 제한
Quota는 보통 API Product 단위 또는 Developer App 단위로 거는 비즈니스 정책입니다. "Free 플랜은 하루 1만 건, Premium은 하루 100만 건"을 구현하는 핵심 도구입니다.
<Quota async="false" continueOnError="false" enabled="true" type="calendar" xmlns="http://www.sap.com/apimgmt">
<DisplayName>Quota-PerApp-DailyTier</DisplayName>
<Identifier ref="verifyapikey.VerifyAPIKey.client_id" />
<Allow countRef="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.limit" count="10000" />
<Interval ref="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.interval">1</Interval>
<TimeUnit ref="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.timeunit">day</TimeUnit>
<StartTime>2026-01-01 00:00:00</StartTime>
<Distributed>true</Distributed>
<Synchronous>false</Synchronous>
</Quota>
여기서 가장 중요한 패턴은 countRef로 API Product에 정의된 quota 값을 동적으로 읽어오는 것입니다. Product 정의에서 Free=10000, Premium=1000000을 설정해두면 같은 정책 XML 하나로 전 플랜을 처리할 수 있습니다.
Distributed=true는 멀티 게이트웨이 노드가 카운트를 공유하도록 합니다. 운영 환경에서는 반드시 켜야 하며, 그렇지 않으면 노드 수만큼 한도가 곱해져 들어옵니다. type="calendar"는 고정 시작점부터 카운팅하며, "rollingwindow"로 바꾸면 슬라이딩 윈도우로 동작합니다.
5. Spike Arrest 정책 — 순간 폭주 차단
Spike Arrest는 가장 가벼운 첫 번째 방어선입니다. 분산 카운팅을 하지 않고 노드별로 즉시 판단하므로 응답 지연이 거의 없습니다.
<SpikeArrest async="false" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<DisplayName>SA-Frontline-30ps</DisplayName>
<Identifier ref="client.ip" />
<MessageWeight ref="request.header.weight" />
<Rate>30ps</Rate>
</SpikeArrest>
여기서 가장 많이 오해하는 부분 — 30ps는 "1초에 30건"이 아니라 "약 33ms당 1건"으로 균등 분산된 흐름만 통과시킵니다. 즉 1초 시작 시점에 30건이 한꺼번에 들이닥치면 첫 1건만 통과하고 나머지 29건은 모두 SpikeArrestViolation으로 거절됩니다.
이게 바로 Spike Arrest의 핵심 가치입니다. burst를 평탄화하는 것이 아니라 burst 자체를 거부해서 백엔드의 thread pool, DB connection이 갑자기 동나는 것을 막아줍니다. 정상적인 사용자라면 33ms 간격은 인지하지 못하므로 UX에 영향이 없습니다.
참고로 Rate는 30ps(per second) 또는 1800pm(per minute) 형식으로 지정할 수 있습니다. pm은 1초 단위로 균등 분산되므로 좀 더 관대한 통과 패턴이 됩니다.
6. 정책 조합 전략 — Spike Arrest + Quota 같이 쓰기
실전에서는 단일 정책으로는 부족합니다. 일반적으로 권장되는 다층 방어 패턴은 다음과 같습니다.
- 1차 (PreFlow 최상단) — Spike Arrest로 비정상 burst 즉시 차단. IP 또는 client_id 기준
- 2차 (VerifyAPIKey 직후) — Quota로 비즈니스 플랜 한도 체크. API Product 값 동적 참조
- 3차 (선택) — Rate Limit으로 분당 처리량 평탄화. 백엔드가 약한 경우만
순서가 중요합니다. Spike Arrest를 가장 먼저 배치해야 인증 모듈(VerifyAPIKey, OAuth2)이 폭주 트래픽에 노출되지 않습니다. 인증은 의외로 비싼 작업이라 여기서 막히면 의미가 없습니다.
<!-- PreFlow 흐름 (의사 코드) -->
<PreFlow name="PreFlow">
<Request>
<Step><Name>SA-Frontline-30ps</Name></Step>
<Step><Name>VerifyAPIKey</Name></Step>
<Step><Name>Quota-PerApp-DailyTier</Name></Step>
<Step><Name>RL-PerClientIP-1000pm</Name></Step>
</Request>
</PreFlow>
한 가지 팁 — Quota는 호출이 백엔드까지 도달했는지 여부와 무관하게 카운트됩니다. 만약 백엔드가 5xx로 실패한 호출은 Quota에서 제외하고 싶다면 Synchronous="false"로 두고 PostFlow에서 조건부 ResetQuota 정책으로 되돌리는 패턴을 씁니다.
7. 에러 핸들링 — 429 응답 커스터마이징
기본 거절 응답은 XML 또는 plain text로 내려와서 모바일/SPA 클라이언트가 파싱하기 불편합니다. RaiseFault 정책으로 JSON 응답을 표준화하는 것이 권장됩니다.
<!-- Fault Rule for SpikeArrestViolation / RateLimitViolation / QuotaViolation -->
<FaultRules>
<FaultRule name="ThrottleFault">
<Condition>(fault.name = "SpikeArrestViolation") or (ratelimit.RL-PerClientIP-1000pm.failed = "true") or (ratelimit.Quota-PerApp-DailyTier.exceeded = "true")</Condition>
<Step><Name>RaiseFault-429</Name></Step>
</FaultRule>
</FaultRules>
{
"error": {
"code": "TOO_MANY_REQUESTS",
"status": 429,
"message": "API call limit exceeded. Please retry after the indicated period.",
"retryAfterSeconds": 60,
"docUrl": "https://developer.example.com/limits"
}
}
흔한 실수 FAQ
- Q. Quota가 노드별로 따로 세지는 것 같아요 — A.
Distributed=true와Synchronous=true를 확인하세요. 동기 분산 카운팅이 켜져야 정확합니다(약간의 지연 비용 발생). - Q. Spike Arrest 30ps인데 25건만 보내도 거절돼요 — A. 30ps는 33ms 간격 강제입니다. 거의 동시에 25건을 쏘면 24건이 거절됩니다. 클라이언트에 jitter나 backoff를 넣으세요.
- Q. Rate Limit Identifier에 client.ip를 썼더니 회사 NAT 뒤에서 한 명이 다 써버려요 — A. 인증된 API Key 또는 OAuth client_id 기반으로 바꾸세요.
verifyapikey.{policy}.client_id가 일반적입니다. - Q. 429를 받으면 클라이언트가 무한 재시도해서 더 망가져요 — A. 응답에
Retry-After헤더를 넣고, 클라이언트는 exponential backoff + jitter를 구현해야 합니다.
8. 핵심 한 줄 (요약)
Spike Arrest로 burst를 막고, Quota로 비즈니스 한도를 강제하고, Rate Limit으로 미세 조정한다 — 이 세 줄이 BTP API Management 트래픽 방어의 전부입니다.
다음 단계로는 ① Custom Attribute를 활용한 동적 Quota(Premium/Free 플랜 분기), ② Cloud Logging Service와 연동한 정책 위반 알람, ③ Generative AI Hub 앞단에 토큰 단위 weight를 적용한 비용 가드 패턴을 학습해보시기를 권장합니다. 특히 LLM API는 토큰당 과금이라 단순 호출 카운팅으로는 비용 통제가 안 됩니다 — MessageWeight를 입력 토큰 수에 비례시키는 것이 권장 패턴입니다.
참고 자료입니다.
- SAP Help — Rate Limit Policy
- SAP Help — Quota Policy
- SAP Help — Spike Arrest Policy
- SAP Help — Policies Overview
- SAP Developers — API Management Tutorials
- SAP Community Blogs — API Management Tag
- SAP Help — Raise Fault Policy (429 커스터마이징)
