밤빵's 개발일지
[WIL]20240922 API Rate Limiting 본문
▶ API Rate Limiting이란?
API Rate Limiting은 클라이언트가 API에 보낼 수 있는 요청 횟수를 제한하는 기술이다. API는 여러 클라이언트로부터 요청을 받으며, 트래픽이 과도해지면 서버에 부하가 걸려 성능이 저하되거나 다운될 위험이 있다. 이를 방지하고 서버 성능을 보호하기 위해 일정 시간 내에 클라이언트가 보낼 수 있는 요청 수를 제한하는 것이 Rate Limiting의 목적이다. 예를 들어, 특정 API가 1분에 100번의 요청만 허용한다고 설정하면, 클라이언트가 그 이상 요청을 보낼 경우 해당 클라이언트는 일정 시간이 지나기 전까지 추가적인 요청을 처리받지 못하게 된다.
▶API Rate Limiting이 필요한 이유
Rate Limiting은 API의 안정성과 성능을 보장하는 데 중요한 역할을 한다.
→ 서버 보호
트래픽이 폭주하거나 악의적인 클라이언트가 무리하게 요청을 보내는 경우 서버 자원이 고갈될 수 있다. Rate Limiting은 이러한 상황을 방지하여 서버가 지속적으로 작동할 수 있도록 한다.
→ 서비스의 공정한 사용 보장
한 클라이언트가 API를 과도하게 사용하는 경우, 다른 클라이언트가 공정하게 자원을 이용할 수 없게 된다. Rate Limiting은 모든 클라이언트가 공평하게 서비스를 이용하도록 보장하는 데 유용하다.
→비용 절감
과도한 API 요청을 제한하지 않으면, 클라우드 서버 비용이나 네트워크 비용이 증가할 수 있다. Rate Limiting은 이를 줄여주는 효과가 있다.
▶Rate Limiting의 작동 방식
API Rate Limiting을 구현하는 방법에는 여러 가지가 있다.
→ Fixed Window (고정 윈도우)
특정 시간 동안 허용된 요청 수를 제한하는 방식이다. 예를 들어 1분 동안 100번의 요청만 허용한다면, 1분이 지나기 전까지 그 이상 요청을 처리하지 않는다.
→ Sliding Window (슬라이딩 윈도우)
고정된 시간 범위 대신 시간 창을 점차 이동시키며 요청을 제한하는 방식이다. 고정 윈도우 방식의 문제점을 보완한다.
→ Token Bucket (토큰 버킷)
토큰이 일정한 속도로 채워지고, 각 요청이 토큰을 소비하는 방식이다. 토큰이 남아있으면 요청을 처리하고, 토큰이 없으면 요청을 거부한다. 이 방식은 유연하게 요청을 관리하는 데 적합하다.
▶ API Rate Limiting 구현
Jakarta EE 환경에서 API Rate Limiting을 구현하는 방법은 여러 가지가 있지만, Guava 라이브러리와 Jakarta EE의 서블릿 필터 및 인터셉터를 활용하는 방법으로 구현해봤다.
▽ Guava Rate Limiter와 서블릿 필터 사용 예시
import com.google.common.util.concurrent.RateLimiter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/limited-api")
public class RateLimitFilter implements Filter {
// 초당 1개의 요청만 허용
private final RateLimiter rateLimiter = RateLimiter.create(1.0);
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 요청 허용 여부를 확인
if (rateLimiter.tryAcquire()) {
chain.doFilter(request, response); // 요청을 계속 진행
} else {
response.getWriter().write("Too many requests - try again later");
response.getWriter().flush();
}
}
@Override
public void destroy() {}
}
→ Jakarta EE의 서블릿 필터(Servlet Filter)를 사용하여 Rate Limiting을 구현한 예시. 필터는 요청을 가로채 처리할 수 있는 Jakarta EE의 컴포넌트로, RateLimiter를 사용하여 초당 1개의 요청만 허용하도록 설정했다. 요청이 허용되지 않으면 클라이언트에게 "Too many requests"라는 메시지를 반환한다.
▶ 인터셉터를 사용한 Rate Limiting
인터셉터(Interceptor)를 사용해 API Rate Limiting을 좀 더 유연하게 적용할 수 있다. IP를 기준으로 Rate Limiting을 적용하는 예시를 만들었다.
import jakarta.annotation.Priority;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import java.util.concurrent.ConcurrentHashMap;
@RateLimited
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class RateLimitingInterceptor {
private final ConcurrentHashMap<String, Long> requestCounts = new ConcurrentHashMap<>();
private static final long MAX_REQUESTS_PER_MINUTE = 10;
@AroundInvoke
public Object limitRate(InvocationContext context) throws Exception {
String clientIP = context.getContextData().get("clientIP").toString();
Long requestCount = requestCounts.getOrDefault(clientIP, 0L);
if (requestCount > MAX_REQUESTS_PER_MINUTE) {
throw new RateLimitException("Too many requests");
}
requestCounts.put(clientIP, requestCount + 1);
return context.proceed();
}
}
→ Jakarta EE의 인터셉터를 사용하여 IP 기반 Rate Limiting을 구현한 예시로, @RateLimited라는 커스텀 어노테이션을 사용해서 Rate Limiting을 적용할 메서드를 지정할 수 있고, 1분 동안 10개의 요청을 허용하도록 제한하고 있다.
▶결론
API Rate Limiting은 서버 자원을 보호하고 서비스의 안정성을 보장하는 중요한 기법이다. Jakarta EE 환경에서 이를 구현하는 방법으로 Guava RateLimiter와 서블릿 필터, 인터셉터를 사용해 적용할 수 있었다. Rate Limiting을 적용하면 클라이언트의 과도한 요청으로부터 서버를 보호하고, 안정적인 서비스를 유지할 수 있다.
'개발Article' 카테고리의 다른 글
[TIL]20240924 H2 데이터베이스 사용법 (2) | 2024.09.24 |
---|---|
[TIL]20240923 클린 코드(Clean Code)작성 원칙 (0) | 2024.09.23 |
[TIL]20240921 SQL&NoSQL 데이터베이스 (0) | 2024.09.21 |
[TIL]20240920 리플렉션(Reflection)의 활용 (2) | 2024.09.20 |
[TIL]20240919 REST 와 SOAP (0) | 2024.09.19 |