JSCODE Logo
프로그래밍 과외블로그후기멘토진
회사명 : JSCODE대표 : 박재성사업자 등록번호 : 244-22-01557통신판매업 : 제 2023-인천미추홀-0381 호
학원 명칭 : 제이에스코드(JSCODE)원격학원학원설립ㆍ운영 등록번호 : 제6063호

서울특별시 구로구 경인로 20가길 11(오류동, 아델리아)

Copyright ⓒ 2025 JSCODE - 최상위 현업 개발자들의 프로그래밍 교육 All rights reserved.

이용약관개인정보처리방침
← 블로그 목록으로 돌아가기

[실습] 악의적인 요청을 방지하기 위해, 10초당 API 요청 횟수를 5회로 제한하기 - 2

JSCODE 박재성
JSCODE 박재성
2026-01-12
author
JSCODE 박재성
category
Redis
createdAt
Jan 12, 2026
series
비전공자도 이해할 수 있는 Redis 중급/실전
slug
rate-limit-api-requests-with-redis-part-2
type
post
updatedAt
Jan 12, 2026 12:24 AM

✅ 실습하기

  1. 코드 작성하기
    1. RateLimiter
      @Component public class RateLimiter { private static final long RATE_LIMIT_TIME_MS = 10_000; // 요청을 카운팅하는 시간 단위 private static final long MAX_REQUESTS = 5; // 10초 동안 최대 5개의 요청만 허용 private final RedisTemplate<String, String> redisTemplate; public RateLimiter(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } public boolean allow(String userId) { long now = System.currentTimeMillis(); // user 단위로 API 요청 횟수를 제한하기 위해, userId를 기반으로 Key를 생성 // (IP 단위로 API 요청 횟수를 제한하고 싶다면, userId 대신 IP를 파라미터로 받으면 된다.) String redisKey = "rate_limit:" + userId; // 서로 다른 요청을 구분하기 위해 UUID로 requestId 값을 생성 String requestId = UUID.randomUUID().toString(); // 1. Soted Set에서(redisKey)에서 score가 0 이상이고 (now - 10_000) 이하인 모든 member를 삭제 // = 최근 10초 내에 저장한 member만 남겨두고, 나머지 member는 전부 삭제 redisTemplate .opsForZSet() .removeRangeByScore(redisKey, 0, now - RATE_LIMIT_TIME_MS); // 2. 현재 들어온 API 요청을 Sorted Set에 저장. // member를 UUID 기반으로 생성된 고유의 requestId로 저정하고, // score를 현재 시간값(ex. 1735972805123)으로 저장한다. // SortedSet에 저장하는 것이기 때문에 score를 기준으로 자동 정렬돼서 저장된다. redisTemplate .opsForZSet() .add(redisKey, requestId, now); // 3. Sorted Set에 저장되어 있는 데이터 개수 조회 // = 최근 10초 내에 요청을 보낸 횟수 Long count = redisTemplate .opsForZSet() .size(redisKey); // 4. 만료 시간(TTL)을 10초로 설정함으로써 // Redis 공간을 불필요하게 많이 점유하는 것을 방지 redisTemplate.expire( redisKey, 10_000, TimeUnit.MILLISECONDS ); // 최대 요청 수보다 작거나 같으면 true를 리턴 // 최대 요청 수를 초과하면 false를 리턴 return count <= MAX_REQUESTS; } }
       
      RateLimitFilter
      // OncePerRequestFilter : HTTP 요청이 들어올 때마다 단 한 번 실행되는 필터 로직 @Component public class RateLimitFilter extends OncePerRequestFilter { private final RateLimiter rateLimiter; public RateLimitFilter(RateLimiter rateLimiter) { this.rateLimiter = rateLimiter; } @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { // 어떤 사용자인지 식별하기 위한 키 // (실무에서는 IP 값을 활용해 식별하는 편) String userId = request.getHeader("USER-ID"); // userId가 null일 땐 RateLimiter가 작동하지 않게 바로 return하기 if (userId == null) { return; } // rateLimiter.allow()가 false라는 건 API 요청 횟수를 초과했다는 뜻이다. // API 요청 횟수가 초과할 경우 429(TOO MANY REQUESTS)로 응답하게 된다. if (!rateLimiter.allow(userId)) { response.setStatus(429); return; } filterChain.doFilter(request, response); } }
       
  1. 서버 실행시키기
    1. notion image
       
  1. Postman으로 요청 보내보기
    1. API 요청 횟수를 잘 제한시켜주는 지, Postman을 활용해 10초 안에 5회가 넘는 요청을 보내보자.
      notion image
      notion image
      정상적으로 API 요청 횟수 제한 기능이 잘 작동하는 걸 확인할 수 있다.
 
author
category
Redis
createdAt
Jan 12, 2026
series
비전공자도 이해할 수 있는 Redis 중급/실전
slug
type
series-footer
updatedAt
Jan 12, 2026 12:26 AM
📎
이 글은 비전공자도 이해할 수 있는 Redis 중급/실전 강의의 수업 자료 중 일부입니다.