[Spring Boot] 특정 IP 일정 요청 횟수 제한

어디든 배우자·2023년 12월 22일

과부하 방지를 위해, 게시글 조회수를 구현 할 당시 쿠키를 통해 조회수 증가를 막는 API를 만들었다. 최근 대용량 트래픽 처리에 관심이 생겨, 우선 내가 할 수 있는 일을 찾았다.
그 결과, 꼭 조회수가 아니더라도 쿼리문이 계속해서 발동하기 전에 막을 수 있다면 트래픽 부분에 도움을 줄 수 있다 생각했다.

요청 횟수가 미리 정의된 한도를 초과하면 해당 IP를 차단해 보자!

상수 및 변수

너는 몇 초 안에 n번의 API가 발동하면 몇 초 동안 차단할꺼니?

public static final long TIME_WINDOW_MILLISECONDS = 2000; // 2초 동안
public static final int MAX_REQUESTS = 4; //4번의 API가 발동하면
public static final long BLOCKING_TIME_MILLISECONDS = 5000; // 5초 동안 너를 막겠다!
 private final ConcurrentHashMap<String, AtomicInteger> requestCountMap = new ConcurrentHashMap<>();

각 IP 주소에 대한 요청 횟수

 private final ConcurrentHashMap<String, Long> blockedIpMap = new ConcurrentHashMap<>();

차단된 IP 및 종료시간
이렇게 사용 될 상수와 변수들을 생성해 줍니다.

API 요청 처리 전

실제 API 요청 처리 전에 호출되는 메서드를 만들어야 합니다.
IP 주소가 차단되었는지, 그렇지 않으면 해당 IP의 요청 횟수를 증가시킵니다.
이제 우리가 허용한 요청 횟수를 초과하면 IP가 시켜야 합니다.

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
      
        String ipAddress = getClientIP(request);

        if (isIpBlocked(ipAddress)) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("IP is temporarily blocked. Please try again later.");
            return false;
        }

        AtomicInteger requestCount = requestCountMap.computeIfAbsent(ipAddress, k -> new AtomicInteger(0));

    
        if (requestCount.incrementAndGet() > WebConstants.MAX_REQUESTS) {
            blockIp(ipAddress);
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("Too many requests. IP blocked for a short duration.");
            return false;
        }

     
        resetRequestCountAfterTimeWindow(ipAddress);

        return true;
    }
profile
다 흡수하기.

0개의 댓글