Lewis's Tech Keep

[Ratelimiter] 처리율 제한 장치 본문

JAVA/Spring

[Ratelimiter] 처리율 제한 장치

Lewis Seo 2024. 7. 8. 02:20

처리율 제한 장치(rate limiter)란?

클아이언트 또는 서비스가 보내는 트래픽의 처리율(rate)을 제어하기 위한 장치

 

특징

  • 특정 기간 내에 전송되는 클라이언트의 요청 횟수를 제한
  • 요청 횟수가 임계치를 넘어가면 추가로 도달한 모든 호출은 처리가 중단(block)

 

이점

  • DoS 자원 고갈 방지
  • 비용 절감
    • 추가 요청을 block 하기 때문에 더 많은 서버 자원이 필요하지 않게 됨
  • 서버 과부하 방지
    • bot에서 오는 트래픽이나 사용자의 잘못된 이용패턴으로 유발된 트래픽을 걸러내는데 활용

 

요구되는 사항들

  • 낮은 응답시간
  • 가능한 적은 메모리
  • 분산형 처리율 제한
  • 여러 서버나 프로세스에서 공유
  • 예외 처리 - 발생한 경우에 사용자에게 분명히 보여주기
  • 높은 fault tolerance : 제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어선 안됨

 


처리율 제한 알고리즘

  • 토큰 버킷(token bucket)
  • 누출 버킷(leaky bucket)
  • 고정 윈도우 카운터(fixed window log)
  • 이동 윈도우 로그(sliding window log)
  • 이동 윈도우 카운터(sliding window counter)

 

토큰 버킷

    • 지정된 용량의 컨테이너를 가지고 있음
    • 토큰이 꽉 찬 버킷에는 더 이상의 토큰은 추가되지 않음
    • 넘치면 추가 공급된 토큰이 버려짐

https://medium.com/@ankitsheoran127201/rate-limiter-design-9ef126c7e030

누출 버킷

토큰 버킷 알고리즘과 비슷하지만 요청 처리율이 고정되어 있음(생각해봣는데 비유동적으로도 가능할듯), FIFO 큐로 구현

  • 요청이 도착하면 큐가 가득차 있는지 확인, 빈자리가 있는 경우에는 큐에 요청을 추가
  • 큐가 가득 차 있으면 새 요청을 버림
  • 지정된 시간마다 큐에서 요청을 꺼내어 처리 (굳이 고정으로 안해도 될듯?)
    https://www.alibabacloud.com/blog/detailed-explanation-of-guava-ratelimiters-throttling-mechanism_594820

 

고정 윈도우 카운터 알고리즘 (fixed window counter)

resilience4j ratelimiter 사용 방식

  • 타임라인을 고정된 간격의 윈도(window)로 나누고 각 윈도마다 카운터(counter)를 붙인다.
  • 요청이 접수될 때마다 카운터의 값은 1씩 증가함
  • 카운터의 값이 사전에 설정된 임계치에 도달하면 새로운 요청은 새 윈도가 열릴 때까지 버려짐
  • 경계 부근에서 일시적으로 많은 트래픽이 몰려드는 우 기대했던 시스템의 처리 한도보다 많은 양의 요청을 처리하게 됨

https://www.codereliant.io/rate-limiting-deep-dive/

이동 윈도 로깅 알고리즘

Spring Cloud Gateway RateLimiter 방식

  • 요청 타임스탬프를 추적한다. 타임 스탬프 데이터는 Redis 같은 캐시에 보관
  • 새 요청이 오면 기존 만료된 타임스탬프 제거
  • 새 요청의 타임스탬프를 로그에 추가함
  • 로그의 크기가 허용치보다 같거나 작으면 통과 아니면 거부

 

  • 다량의 메모리를 사용함
  • 거부된 요청의 타임스탬프도 보관하기 때문
    https://medium.com/@wanguiwawerub/rate-limiting-sliding-window-log-algorithm-bd370b3ad90b

 

이동 윈도 카운터 알고리즘

  • 고정 윈도 카운터 알고리즘과 이동 윈도 로깅 알고리즘을 결합
  • 현재 1분간 요청 수 + 직전 1분간 요청수 * 윈도우간 겹치는 비율

https://software-factotum.medium.com/sliding-window-fixed-rate-practical-rate-limiting-for-web-apis-c8408a070e4c

  • 위 그림 경우 250 + 400 * 0.25가 됨

내가 사용했었던 경험

실제로 인증 서버 & Gateway API에서 어플리케이션 간에서 처리율 제한을 위해 Ratelimiter4j Ratelimiter 라이브러리를 사용했었다.

Resilience4J RateLimiter 설명 중 발췌

 

하지만 kubernetes위에 올라가 있는 멀티 pod들을 관리할 수 있는 처리율을 Redis와 같은 공통 관리 저장소에서 관리한 것은 아니었다.

 

그래서 초당 300개를 받고 싶으면 각 파드 당 처리율 제한을 설정하였다.

 

💡 ex. rate limit 30 = 300 / 10 (pod 개수)

 

이런 형태로 나누어 넣게 되었는데, 이렇게 하니 실제로는 각자 다른 카운트를 세고 있어서 짧은 시간에 엄청 많은 트래픽이 들어오는 경우에 다 같이 처리율 제한 오류를 반환하는 것이 아닌 일부만 독립적으로 반환하는 경우도 있었다.

redis에 데이터를 저장하게 되는 것에 대해 네트워크 용량 및 라이브러리 미제공 이슈로 인한 커스텀 코드 관리 이슈도 같이 있었기에 결국 도입하지는 않았지만 도입하는 것이 필요하다면 바로 도입하는 것이 좋을 것 같다.

생겼던 이슈 정리

  • 파드 개수는 scale-out 이 유연하게 처리하는 경우(ex. auto-scaling) 빠르게 변화할텐데 이때마다 숫자를 바꾸는 것을 신경써야했다.
  • 엄청 짧은 시간에 한쪽 파드에 몰리는 경우 resilience4j ratelimiter는 세마포어로 스레드 단에서 관리되기 때문에 스레드 점유가 높아져 장애가 발생할 수 있었다.
          •  
Comments