Jmeter 를 곁들인 성능 개선기 (1차)

박우영·2023년 10월 11일
0

자바/코틀린/스프링

목록 보기
33/37

들어가기 앞서

저는 실제로 배포를 해보며 사용자 입장에서 기능을 생각해보고, 피드백을 받아보면서 기능을 추가하는 것 뿐만아니라 성능적인 부분도 향상시키고 싶다는 생각이 들었고 성능의 지표를 확인하기 위해 jmeter, k6 와 같은 성능 테스트 도구를 활용하기로 하였습니다.
측정 하기위한 지표는 다음과 같습니다.

  • 응답시간
  • 속도
  • 성공률
  • TPS

코드를 짤때 성능적인 부분을 고려한다고 했지만 아키텍처 적으로도, Application 코드로도 충분히 개선시킬만한 부분이 존재한다고 생각합니다.

지금 이 블로그를 최초 작성할때 당시의 성능을 측정 후 어떻게 더 발전시켜 나가는지 과정을 남겨보며 어떤점들을 개선했는지 기록하고자 합니다.

Jmeter 사용법은 구글링을 좀만하면 찾아볼 수 있고 이 게시글의 주 내용이 아니기때문에 생략하겠습니다.

프로젝트 구성


간단하게 프로젝트 아키텍처를 작성해봤습니다. 우리가 테스트 해볼건 Study Server에 Rest API 요청을 보낼 것 입니다.

비교 대상
1. GCE에 있는 APIGateway를 통해 Study Server에 요청
2. Study Server 에 다이렉트로 요청 (GKE 의 externalIp로 바로 요청)
3. 기존의 모놀리식의 홈페이지 로그인 창

1차 테스트

쓰레드 구성은 다음과 같습니다.

위 쓰레드 요청을 5회 반복 한 결과

  1. Gateway
  1. 바로 요청
  1. Monolithic (index page)

위에도 언급했지만 1,2 번은 동일한 api에 대한 요청이지만 3번은 요청 내용이 다릅니다.

Throughput 을 TPS 라고 생각하고 정의 하고 보기 편하게 테이블로 비교하겠습니다.

평균 응답시간지연시간성공률TPS
Gateway 요청109687~380099.9%15.3/sec
바로 API요청1192120~4000100%15.3/sec
Monolithic9113~860100%15.3/sec

TPS를 확인해보면 최초 200회 요청 시 약 30정도 나오다가 요청이 많아 질 수록 낮아지는 모습이 식별됐습니다.

Thread Properties 수정

이번엔 200명의 사용자가 1회씩 요청 하는 경우 1회 요청으로 테스트

  1. Gateway

  2. 다이렉트 요청

  3. Monolithic

평균 응답시간지연시간성공률TPS
Gateway 요청1742168~520092%34.8/sec
바로 API요청1547120~4000100%32.5/sec
Monolithic6522~420100%35.9/sec

약간의 변화는 있지만 큰 이변은 없는 모습입니다.

요청 방법 수정

어떻게 보면 Gateway 가 요청 보내는곳과 다이렉트로 연결 하는곳이 같은 처리를 해서 TPS가 낮게 나오는 것이 아닌가 라는 생각이 들어서 다시 테스트 해봤습니다.

200요청을 1번씩 보내는 것으로 1회 테스트

  1. Gateway

  2. 다이렉트

평균 응답시간지연시간성공률TPS
Gateway 요청142383~2200100%69.4/sec
바로 API요청95151~2100100%73.2/sec

같은 API에 요청을 보내는데 한번을 보내는 실수로 잘 못된 테스트 값이 나왔었습니다.
하지만 평균 응답시간이 많은 차이를 보이고 있고 TPS도 낮다고 생각이 듭니다.

해결 해야할 목표

  1. TPS 개선
  2. 바로 요청 보낼때와 Gateway 요청의 응답시간 격차 줄이기

1차 개선 사항

불필요 log 삭제 및 logback vs log4j2

Filter

    @Override
    public GatewayFilter apply(Config config) {
        return (((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            log.info("[글로벌 필터] REQUEST >>> IP : {}, URI : {}", request.getRemoteAddress().getAddress(), request.getURI());


            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("[글로벌 필터] RESPONSE >>> IP : {}, URI : {}, Status : {}",
                        request.getRemoteAddress().getAddress(),
                        request.getURI(),
                        response.getStatusCode()
                );
            }));
        }));
    }

Gateway의 filter 부분입니다. Spring cloud gateway 는 webflux로 비동기 처리가 이루어지는 데 log를 보면 @Slf4j 를 사용하고 있습니다. 따라서 구현체인 logback 을 사용하는 것인데요 logback 은 log4j2 에 비해 비동기 처리시 성능저하를 발생 시킬 수 있습니다. 물론 asyncappender 설정을 하지 않은 탓 도 있지만 logback vs log4j2 를 다루기 전에 원인이 로그에 있는지 확인 을 해봤습니다.

200 회 1회 요청 테스트

Gateway

평균 응답시간지연시간성공률TPS
AS-IS142383~2200100%69.4/sec
TO-BE1086143~2000100%73.4/sec

약간의 성능에 영향을 미치는것을 확인 할 수 있었습니다.

Reference

[NHN FORWARD 2020] 내가 만든 WebFlux가 느렸던 이유

0개의 댓글