본문 바로가기

Yonsei Golf

Spring 처리율 제한 장치 (Rate Limiter)

1. 문제 정의

현제 연세대학교 골프동아리 웹사이트는 t2.micro에서 운영되고 있습니다. 사용할 수 있는 CPU는 한정적이기 때문에, 동아리 지원자가 몰리는 지원 마지막날에 대비해야 할 필요가 있습니다.

이번 포스팅에서는 t2.micro 에서 현재 웹 사이트가 버틸 수 있는 vUser의 지원서 작성 한계에 대해 알아보고, 어떻게 문제를 해결할 수 있는지 알아보도록 하겠습니다.

2. 트래픽 한계점

평균 동아리 지원자 200여명을 기준으로, vUser 200을 기준으로 테스트를 해보겠습니다.

image

 

image

CPU 사용률이 50%에 이르며, 218번의 트랜잭션이 발생했지만, 이 중 성공한 트랜잭션은 70개에 불과합니다.

즉 트래픽이 몰릴 경우 테스트의 30%만이 성공하는 것을 확인할 수 있습니다.

이러한 에러가 발생할 경우, 사용자는 자신의 지원서가 제출되었는지 확인하지 못하는 장애를 겪을 수 있습니다.

이를 해결하기 위해 처리율 제한 장치를 도입함으로써, 사용자의 요청이 처리되지 못 한 경우 명확한 에러 메시지를 표시해주도록 하겠습니다.

2. 많이 사용되는 처리율 제한 장치

많이 이용하는 처리율 제한 장치는 네 가지가 있습니다.

  1. Guava
    1. 토큰 버킷 알고리즘을 기반으로 구현된 라이브러리로, 구글에서 개발하였습니다.
    2. 처리율 제한을 목적으로 나온 라이브러리가 아니기 때문에 선택하지 않도록 하겠습니다.
  2. RESILIENCE4J
    1. MSA에서 널리 사용됩니다.
  3. RATE LIMIT J
    image
    1. 이동 윈도우 알고리즘을 기반으로 하는 라이브러리 입니다.
    2. 하지만 GitHub README 에 ‘더 이상 지원하지 않는 프로젝트이니 Bucket4J를 사용하시오’ 라고 명시되어 있기에 사용하지 않겠습니다.
  4. Bucket4J
    1. 토큰 버킷 알고리즘을 기반으로 하는 속도 제한 라이브러리 입니다.
    2. 이번 포스팅에서 적용해보도록 하겠습니다.

3. 도입기

build.gradle 에 다음의 의존성을 추가해줍니다.

implementation 'com.bucket4j:bucket4j-core:8.3.0

BucketConfig 작성

@Configuration
public class BucketConfig {

    @Bean
    public Bucket bucket() {

        Refill refill = Refill.intervally(10, Duration.ofSeconds(60));

        Bandwidth limit = Bandwidth.classic(10, refill);

        return Bucket.builder()
                .addLimit(limit)
                .build();
    }
}

위 설정의 경우 60초 동안 10 개의 요청만을 허용하고, 10개의 동시 요청을 허용하는 버킷을 생성한 것입니다.

과부하 테스트를 통해 확인해보면, 현재 TPS 는 1.8 로 초당 1 ~ 2 개의 지원서를 수신하고, 지원서에 적힌 이메일을 기반으로 지원 확인 이메일을 전송해주고 있습니다.

이는 60초에 90개 이상의 처리를 할 수 있지만, CPU 사용률의 부담, 실질적인 사용자가 그만큼 몰리지 않는다는 점을 고려하여 조금 더 낮게 설정해주겠습니다.

4. 처리율 제한 장치 도입 이후

4년간의 통계를 보면, 지원 마감 30분 전 대략 30여개의 지원서가 도착했습니다.

극단적으로 1분 동안 30개의 지원서가 온다고 생각하고, Bucket에 40개의 여유를 주도록 하겠습니다.

nGrinder에서 테스트를 위해 상태 코드가 200 혹은 429(Too Many Requests)를 반환하는지 테스트 했습니다.

image

 

image

처리율에 제한을 주지 않았던 경우는 계속해서 데이터베이스에 접근하고, 이메일을 전송하기 때문에 CPU에 많은 부하가 가고 TPS가 1.8 정도로 매우 낮은 현상을 보여주었습니다.

하지만 처리율 제한 덕분에 데이터베이스와 SMTP에 접근하기 전에 429에러를 반환해줌으로써, 사용자에게 현재 트래픽이 너무 많이 몰려서 기다려달라는 명확한 메시지를 전달할 수 있게 됨과 동시에 훨씬 더 많은 부하를 견딜 수 있게 되었습니다.

5. 마치며

이번 포스팅에서는 사용자 요청이 많아 요청을 처리할 수 없다는 명확한 오류를 사용자에게 보여주었습니다.

하지만 사용자 입장에서는 여전히 요청은 실패하였고, 다시 지원서를 제출해야 한다는 불편함이 남아있습니다.

다음 포스팅에서는 사용자의 요청 처리를 대기 큐에 넣고, 순차대로 요청을 처리하는 방법에 대해 알아보도록 하겠습니다.

'Yonsei Golf' 카테고리의 다른 글

쿠폰 발급 동시성 제어  (0) 2024.01.04
Email 성능 개선기  (0) 2023.12.09
모니터링 with Docker  (0) 2023.12.09
JWT Token + Refresh Token  (1) 2023.11.27
CloudFront, S3 배포 자동화  (2) 2023.11.26