Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

밤빵's 개발일지

[WIL]20240922 API Rate Limiting 본문

개발Article

[WIL]20240922 API Rate Limiting

최밤빵 2024. 9. 23. 00:01

▶ 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을 적용하면 클라이언트의 과도한 요청으로부터 서버를 보호하고, 안정적인 서비스를 유지할 수 있다.