[Spring] Spring Cache 성능 비교 (feat. Vegeta)

윈도우 환경에서 Spring Cache 사용여부에 따른 성능 비교를 위해 Vegeta라는 툴을 사용해보고자 한다. Cache는 Redis Cache를 사용한다.

local ip 확인해두기

Vegeta 설치 전 명령프롬프트에서 ipconfig를 통해 local의 IPv4 주소를 확인해두자.

Vegeta 설치

윈도우 환경에서 Vegeta 설치를 위해서는 WSL를 이용하여 ubuntu를 설치해줘야 한다.
윈도우에 ubuntu 설치

WSL로 설치한 ubuntu에 접속하고 Vegeta를 설치한다

sudo snap install vegeta

참고 : 스냅(Snap)은 우분투의 개발사인 캐노니컬에서 개발한 패키지 관리 시스템이다

아래 명령어를 통해 스냅으로 설치된 패키지 목록을 확인할 수 있다.

snap list

주요 명령어 및 파라미터

공통 명령어

  • vegeta attack: HTTP 요청을 특정 속도 및 시간 동안 실행하여 부하를 생성.
  • vegeta report: 부하 테스트 결과를 요약 보고서로 출력.

주요 파라미터

vegeta attack [옵션]

-targets: 부하를 보낼 대상 파일 경로.
-rate: 초당 요청 수
-duration: 부하를 지속할 시간.
-timeout: 각 요청의 타임아웃 시간.
-workers: 요청 처리에 사용될 워커(스레드) 수.

간단한 성능 테스트

Vegeta를 설치하고 아래의 명령어를 실행하여 간단히 성능 테스트를 실행해볼수 있다.
5초동안 초당 10회의 GET 요청을 http://example.com으로 보내고 그 결과를 확인하는 명령어이다.

echo "GET http://example.com" | vegeta attack -rate=10 -duration=5s | vegeta report

결과를 통해 총 초당 10.21의 빈도로 50번의 요청을 보냈고 , 5.038s 동안 4.899s 요청을 보내고 138.946ms 동안 응답을 기다렸음을 알 수 있다.

-targets 옵션

위의 예시에서는 http://example.com이라는 단일 타겟으로 GET 요청을 보냈지만, 여러개의 요청을 보내고 싶을 경우 파일에 보낼 요청을 작성하고 -targets 옵션을 통해 해당 파일의 경로를 지정해주면 해당 파일의 요청들을 지정해준 옵션에 따라 보낼 수 있게 된다.

아래와 같이 request.txt 파일을 작성하였다.

GET http://192.168.55.68:8080/users/1
GET http://192.168.55.68:8080/users/2
GET http://192.168.55.68:8080/users/3

명령 작성

공통 명령어와 파라미터를 참조하여 다음과 같이 vegeta attack 명령어를 작성하였다.

최대 20초의 타임아웃으로 100개의 스레드로 10초동안 초당 3천번의 요청을 보낸다.

vegeta attack -timeout=20s -duration=10s -rate=3000/1s -targets=request.txt -workers=100 | vegeta report

위 명령을 한 번은 캐시를 적용시킨 코드를 주석처리하여 빌드 한 다음 실행시키고, 한 번은 캐시를 적용시킨 다음 빌드하여 실행시키면 캐시를 적용하였을 때와 적용시키지 않았을때의 성능 차이를 비교할 수 있게 된다.

@Cacheable(cacheNames = CACHE1, key = "'user:' + #id")
    public User getUserFromCache(final Long id) {
        return userRepository.findById(id).orElseThrow();
    }

위 코드의 @Cacheable 어노테이션을 주석처리 할 경우 캐시가 적용되지 않고 매 요청에 대해 DB에 직접 조회하게 될 것이고, 주석처리 하지 않을 경우 첫 요청에 대해서만 DB에 직접 조회하고 그 이후 요청부터는 Redis에 저장된 캐시를 불러오게 될 것이다.

실행 결과

vegeta 명령어를 캐시 적용 전후 각각 실행하고, 실제 유저 데이터와 캐시데이터가 저장될 redismysql 도커 컨테이너의 리소스 모니터링을 통해 캐시 적용 전후의 CPU 점유율 등을 확인해보았다.

캐시 적용 전

총 24.309s 동안 절반이상의 시간을 응답을 기다리는데 쓰였고, 요청에 대해서는 99.49% 성공했지만 초기 원했던 초당 3000회의 요청에 미치지 못하는 초당 1665.66번의 요청이 수행된것을 알 수 있다. 캐시를 사용하지 않으면 매 요청에 대해 DB에 쿼리를 날리게 되고 그 만큼 부하가 가해지므로 성능이 좋지않음을 알 수 있다.

왼쪽이 redis 컨테이너, 오른쪽이 mysql 컨테이너의 리소스이다. 캐시를 적용하지 않았기 때문에 redis 컨테이너의 CPU 점유율은 거의 변동이 없는 반면 mysql 컨테이너는 70%까지 CPU 점유율이 올라갔다.

캐시 적용 후

같은 요청에 대해 캐시를 적용시켜보니 10.008s 동안 응답 대기 시간은 고작 6.129ms에 불과했고, 초당 2999.40회 요청이 이뤄졌으며 요청이 100% 성공했음을 알 수 있다. mysqlredis의 CPU 점유율 또한 레디스 서버가 한때 6~7%까지 점유율이 올라가긴 하였으나 비교적 안정적으로 유지 되었다. 확실히 캐시를 적용하였을 때 부하가 덜하고 좋은 성능이 나옴을 알 수 있었다.