Rate Limiter 패턴

날아올라돼지야·2024년 8월 29일
0

1. Rate Limiter 패턴 소개

이번 강의에서는 Spring Cloud Gateway를 활용하여 Rate Limiter 패턴을 구현하는 방법을 배웁니다. Rate Limiter 패턴은 시스템에 대한 요청이 일정한 속도를 초과할 때, 해당 요청을 제한하고 HTTP 429 상태 코드를 반환하여 "Too Many Requests" 오류를 발생시킵니다.

2. Rate Limiter 개념 및 주요 구성 요소

Rate Limiter 패턴을 구현하려면 몇 가지 중요한 구성 요소를 이해해야 합니다:

2.1 KeyResolver

KeyResolverRate Limiter가 요청을 제한할 기준을 정의하는 인터페이스입니다. 이 기준은 사용자, 세션, IP 주소 또는 서버 등 다양한 요소에 기반할 수 있습니다.

  • KeyResolver 예시: Spring Security를 사용하여 사용자 인증을 처리하는 경우, PrincipalNameKeyResolver를 사용하여 로그인한 사용자 이름을 기준으로 Rate Limiter를 설정할 수 있습니다.

2.2 Redis 기반 Rate Limiter

Spring Cloud Gateway에서는 Redis를 사용한 Rate Limiter 구현을 지원합니다. Redis는 캐시 기반의 저장 시스템으로, Rate Limiter의 구현에 적합합니다. 이 구현은 Stripe 팀의 작업을 기반으로 하고 있으며, 기본적으로 토큰 버킷(Token Bucket) 알고리즘을 사용합니다.

  • ReplenishRate: 초당 허용할 요청 수를 정의합니다. 예를 들어 replenishRate가 100으로 설정되면, 매 초마다 100개의 토큰이 버킷에 추가됩니다.
  • Burst Capacity: 버킷이 최대 몇 개의 토큰을 저장할 수 있는지를 정의합니다. 예를 들어, burstCapacity가 200으로 설정되면, 버킷에는 최대 200개의 토큰이 저장됩니다.
  • Requested Tokens: 요청 하나당 소모될 토큰 수를 정의합니다. 기본적으로 각 요청은 1개의 토큰을 소모합니다.

3. Rate Limiter 패턴 구현

이제 Rate Limiter 패턴을 Spring Cloud Gateway에 구현해보겠습니다.

3.1 프로젝트 설정

먼저, Redis 기반의 Rate Limiter를 사용하기 위해 Maven pom.xml에 필요한 종속성을 추가합니다.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

3.2 Rate Limiter 설정

이제 Rate Limiter를 설정하기 위해 Java 코드와 Yaml 설정 파일을 사용합니다.

3.2.1 Java 기반 설정

RouteLocator를 설정할 때 Rate Limiter를 추가합니다. 이 예제에서는 사용자의 IP 주소를 기준으로 Rate Limiter를 설정합니다.

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, RedisRateLimiter redisRateLimiter) {
    return builder.routes()
        .route("loans-service", r -> r.path("/loans/**")
            .filters(f -> f
                .requestRateLimiter(c -> c
                    .setRateLimiter(redisRateLimiter)
                    .setKeyResolver(ipKeyResolver())))
            .uri("lb://loans-service"))
        .build();
}

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
  • ipKeyResolver(): 요청자의 IP 주소를 기준으로 Rate Limiter를 설정합니다.
  • RedisRateLimiter: RedisRateLimiter를 사용하여 토큰 버킷 알고리즘을 통해 요청을 제한합니다.
3.2.2 application.yml 설정

application.yml 파일에서 Rate Limiter의 속성을 정의합니다.

spring:
  cloud:
    gateway:
      routes:
        - id: loans-service
          uri: lb://loans-service
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 1
  • replenishRate: 초당 10개의 요청을 허용하도록 설정합니다.
  • burstCapacity: 최대 20개의 요청을 허용하도록 설정합니다.
  • requestedTokens: 각 요청에 1개의 토큰을 소모하도록 설정합니다.

4. 테스트 및 확인

이제 Spring Cloud Gateway를 실행하고, Postman 등을 사용하여 설정한 Rate Limiter가 올바르게 동작하는지 테스트합니다.

4.1 Postman 테스트

Postman에서 설정한 엔드포인트로 여러 개의 요청을 보냅니다. Rate Limiter가 동작하면 초과된 요청에 대해 HTTP 429 Too Many Requests 응답을 반환합니다.

GET /loans/contact-info
Status: 429 Too Many Requests

4.2 Redis 모니터링

Redis를 모니터링하여 토큰이 어떻게 관리되고 있는지 확인할 수 있습니다. Redis CLI를 사용하여 관련 키와 값을 확인할 수 있습니다.

redis-cli
> KEYS *
> GET <your_key>

5. 요약

이번 강의에서는 Spring Cloud Gateway를 사용하여 Rate Limiter 패턴을 구현하는 방법을 배웠습니다. Redis를 활용하여 Rate Limiter를 설정하고, KeyResolver를 통해 사용자 정의 제한 조건을 설정했습니다. 이 구현을 통해 트래픽을 효과적으로 관리하고 시스템의 안정성을 유지할 수 있습니다.

6. 최종 코드

6.1 RouteLocator 설정

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, RedisRateLimiter redisRateLimiter) {
    return builder.routes()
        .route("loans-service", r -> r.path("/loans/**")
            .filters(f -> f
                .requestRateLimiter(c -> c
                    .setRateLimiter(redisRateLimiter)
                    .setKeyResolver(ipKeyResolver())))
            .uri("lb://loans-service"))
        .build();
}

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}

6.2 application.yml 설정

spring:
  cloud:
    gateway:
      routes:
        - id: loans-service
          uri: lb://loans-service
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 1

이제 Spring Cloud Gateway를 사용하여 시스템의 트래픽을 효율적으로 제한하고 관리할 수 있게 되었습니다. 이 설정을 통해 서버 리소스를 보호하고, 악성 또는 과도한 요청으로 인한 장애를 방지할 수 있습니다.

profile
무슨 생각하며 사니

0개의 댓글