ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Jmeter 성능테스트를 통한 Thread pool 및 webclient의 동기적처리 사용 여부 결정
    spring 2024. 2. 16. 16:07
    반응형

    서론

     

    테스트 설계전 오류 발생과 해결 과정

     

    서비스 흐름

    1. 클라이언트로부터 캐릭터 닉네임, 날짜 데이터를 입력 받는다.

    2. 컨트롤러에서 서비스 클래스의 메서드를 실행시킨다.

    3. 서비스 클래스의 메서드에서 maplestory openapi 호출을 하여 닉네임을 입력하고 고유 키를 전달 받는다.

     

    고려한 사항.

     1. 서비스 코드에는 RateLimiter 설정이 되어있고, 분당 300건의 호출 제한을 가진다.

     - 이유: maplestory openapi의 초당 호출 제한이 5건/초 이지만 메서드에서 필터를 통해 모든 호출을 바로 보내지 않기 때문에 적정 수준으로 설정.

    2. 서비스 코드에서 webclient를 사용하여 비동기 방식으로 사용한다.

     - 이유: 먼저 RestTemplate을 사용하였으나 spring5 버전 이후 나온 webclient가 좀 더 유연하게 사용할 수 있는 코드라 생각해서 수정.

     

    => 코드를 수정한 후  webclient 는 사용할때 오류 발생.

     

    webclient와 Threadpool 을 사용한 이유?

     

    1. 여러명의 사용자가 한번에 검색을 하는 상황을 가정했을 때, 쓰레드 풀을 사용하여 미리 기본 쓰레드 숫자와 최대 쓰레드 숫자를 설정하는 것이 필요하다 생각했다.

    2. @Configuration에 해당 내용을 설정하고 이를 @Async 를 통하여 적용할 생각이었다.

    3. webclient를 사용한 서비스 클래스의 메서드에 이를 적용하였다. -다중 사용자가 호출하는 상황에서 쓰레드 풀이 필요하다 생각함.

     

    => @Async없는 코드를 불러올 경우 정상 데이터가 반환되지만 붙일경우 null값이 반환되는 문제가 생겼다.

     

    오류 원인 

     

    => webclient는 @Async를 붙여서 사용할 경우 적절한 반환을 기다리지 않고 미리 반환되어 null값이 들어갈 수 있다.

     

    수정 방향성

    @Async를 사용하는 상황일때 제대로 된 반환값이 오기를 기다리게 하는 동기적인 과정이 필요하다.

    따라서 반환값을 Mono에서 CompletableFuture로 수정하고 .subscribe를 추가하여 동기적인 과정을 거쳤다.

    => 동기적인 과정을 거친 결과 데이터는 문제 없이 반환되었다.

     

    수정 방향성에 대한 의문

    webclient를 사용한 이유는 비동기적인 방식이 호출 속도가 더 빠르고 효율적인 과정이라 생각해서 였다.

    그러나 subscribe를 추가하면 결국 동기적인 방식을 추가한 것이라서 의미가 퇴색되지 않을까?

    한편, Thread pool은 여러 사용자가 동시에 호출했을 때 추가 쓰레드를 계속 생성하여 결국 프로세스가 종료되는 문제를 야기하는데 이 문제를 방지하기 위해 사용하였다.

    즉, @Async는 Thread pool을 사용하기 위해서 쓰는건데, 이를 붙이면 webclient의 비동기적인 방식을 온전히 사용하기 어렵다. 그렇다고@Async를 아예 사용하지 않을 경우 스레드의 생성이 예상보다 많이 증가할 수도 있다는 문제가 있다.

     

    여러 검색을 통해 찾아본 결과 내가 바꿀 수 있는 수준에서는 위의 두가지 방법이 전부였다.

    따라서 내가 느끼기에 Thread pool은 서버의 안정성 측면에 좀 더 비중이 있고, webclient를 사용하는 비동기적 방법의 경우에는 성능의 측면에 비중이 있다고 생각한다. 이 두가지가 충돌할 경우 우선 안정성을 생각하는 것이 맞다고 생각하였고, Thread pool 을 사용하면서 동기적인 방법으로 값을 반환받는 방법을 선택하였다.

     

    본론

    테스트를 통한 검증

     

    결국 webclient에 subscribe를 추가하여 동기적인 방식을 추가할때 고민되는 부분이 성능의 하락이라 생각한다.

    따라서 Jmeter를 통해 성능의 차이가 얼마나 생기는지 확인해보았다.

     

    A방법  /maplestory/v1/id  - 스레드 풀 사용,webclient에 동기적인 처리. RateLimt 분당 300회 제한

     

    테스트 설계 1. 저부하 테스트

    쓰레드 10, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

    1차

    2차

    3차

     

    3회 실행 평균

    표본 : 50 평균 : 225 95%선 : 872 99%선 : 912 오류 : 84% 처리량 : 51.4/sec 수신KB/초 : 102.69 전송KB/초 : 8.47

     

    테스트 설계 2. 중간 부하 테스트

    쓰레드100, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

    1차

     

    2차

     

    3차

     

    3회 실행 평균

    표본 : 500 평균 : 292 95%선 : 987 99%선 : 1608 오류 : 98% 처리량 : 271.53/sec 수신KB/초 : 1325.32 전송KB/초 : 44.76

     

    테스트 설계 3. 고 부하 테스트

    쓰레드1000, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

     

    1차

     

    2차

    3차

     

    3회 실행 평균

    표본 : 5000 평균 : 2229 95%선 : 3404 99%선 : 5839 오류 : 99.57% 처리량 : 827.13/sec 수신KB/초 : 5656.12 전송KB/초 : 131.48

     

    B방법  /maplestory/v1/  - 스레드 풀 사용X,webclient를 비동기적으로 그대로 사용. RateLimt 분당 300회 제한

     

    테스트 설계 1. 저 부하 테스트

    쓰레드 10, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

    1차

    2차

    3차

    3회 실행 평균

    표본 : 50 평균 : 158 95%선 : 911 99%선 : 982 오류 : 90.6% 처리량 : 44.7/sec 수신KB/초 : 261.43 전송KB/초 : 7.28

     

    테스트 설계 2. 중간 부하 테스트

    쓰레드100, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

     

    1차

    2차

    3차

    3회 실행 평균

    표본 : 500 평균 : 77.33 95%선 : 280 99%선 : 1133 오류 : 99.33% 처리량 : 361.56/sec 수신KB/초 : 2103.08 전송KB/초 : 58.89

     

    테스트 설계 3. 고 부하 테스트

    쓰레드1000, 루프카운트1 을 하나의 쓰레드 그룹으로 하여 5개의 그룹 생성. 각 그룹의 param 값은 모두 다르고 유효하지 않은 param도 들어있음. 각 테스트 전에 db 내용 초기화 후 진행. 오차를 줄이기 위해 각 단계마다 3회 테스트 실행.

     

    1차

    2차

    3차

    3회 실행 평균

    표본 : 5000 평균 : 1241.66 95%선 : 1811.33 99%선 : 2136.66 오류 : 99.93% 처리량 : 152.63/sec 수신KB/초 : 814.54 전송KB/초 : 21.43

     

    테스트 결과 정리

     

    (참고, 오류% 자체가 큰 이유는 RateLimit를 분당 300회 제한으로 설정했는데 이를 크게 상회하는 요청을 테스트 했기 때문.)

     

    A방법 /maplestory/v1/id  - 스레드 풀 사용0 RateLimt 분당 300회 제한

    표본 : 50 평균 : 225 95%선 : 872 99%선 : 912 오류 : 84% 처리량 : 51.4/sec 수신KB/초 : 102.69 전송KB/초 : 8.47

    표본 : 500 평균 : 292 95%선 : 987 99%선 : 1608 오류 : 98% 처리량 : 271.53/sec 수신KB/초 : 1325.32 전송KB/초 : 44.76

    표본 : 5000 평균 : 2229 95%선 : 3404 99%선 : 5839 오류 : 99.57% 처리량 : 827.13/sec 수신KB/초 : 5656.12 전송KB/초 : 131.48

    B방법 /maplestory/v1/  - 스레드 풀 사용X RateLimt 분당 300회 제한

    표본 : 50 평균 : 158 95%선 : 911 99%선 : 982 오류 : 90.6% 처리량 : 44.7/sec 수신KB/초 : 261.43 전송KB/초 : 7.28

    표본 : 500 평균 : 77.33 95%선 : 280 99%선 : 1133 오류 : 99.33% 처리량 : 361.56/sec 수신KB/초 : 2103.08 전송KB/초 : 58.89

    표본 : 5000 평균 : 1241.66 95%선 : 1811.33 99%선 : 2136.66 오류 : 99.93% 처리량 : 152.63/sec 수신KB/초 : 814.54 전송KB/초 : 21.43

     

    표본 50일때 (저부하 상태)

    A 평균 : 225 95%선 : 872 99%선 : 912 오류 : 84% 처리량 : 51.4/sec 수신KB/초 : 102.69 전송KB/초 : 8.47

    B 평균 : 158 95%선 : 911 99%선 : 982 오류 : 90.6% 처리량 : 44.7/sec 수신KB/초 : 261.43 전송KB/초 : 7.28

     

    표본 500일때 (중간 부하 상태)

    A 평균 : 292    95%선 : 987  99%선 : 1608  오류 : 98%       처리량 : 271.53/sec   수신KB/초 : 1325.32  전송KB/초 : 44.76

    B 평균 : 77      95%선 : 280   99%선 : 1133  오류 : 99.33%  처리량 : 361.56/sec  수신KB/초 : 2103.08   전송KB/초 : 58.89

     

    표본 5000일때 (고 부하 상태)

    A 평균 : 2229   95%선 : 3404     99%선 : 5839   오류 : 99.57%  처리량 : 827.13/sec   수신KB/초 : 5656.12 전송KB/초 : 131.48

    B 평균 : 1241    95%선 : 1811       99%선 : 2136    오류 : 99.93%  처리량 : 152.63/sec   수신KB/초 : 814.54  전송KB/초 : 21.43

     

    정리

    저 부하 상태인 표본 50상태에서 A가 B 보다 초당 처리량은 많고 및 99%선 지수는 낮은것으로 보아 효율이 근소 우위에 있다고 볼 수 있다. A>=B

    중간 부하 상태인 표본 500상태에선 B가A보다 초당 처리량이 많고 99%선 지수는 낮은 것으로 보아 처리 속도와 효율면에서 더 우위에 있다고 볼 수 있다. B>=A

    고 부하 상태인 표본 5000인 상태에서 B가A보다 초당 처리량은 확연히 적지만 99%선 지수는 낮은 것으로 보아 처리에 걸린 시간 자체는 더 빨랐다고 볼 수 있다. B>A

     

    한계점

    우선 이 테스트 결과에는 많은 변수가 있다.

    1. 서버를 가동시키는 컴퓨터와 테스트 컴퓨터가 동일하다. 정확한 테스트를 위해서는 다른 컴퓨터에서 해야 하는데 동일 컴퓨터에서 한 한계가 있다.

    2. 테스트마다 편차가 크다. 편차를 줄이기 위해 표본수당 3회를 측정하고 평균값을 내었지만 이정도 표본으로는 많이 부족하다.

    3. 스레드풀 설정이 최적화 되어있지 않다. 현재 스레드풀 설정은 기본 스레드 8 맥스 스레드 16 대기용량 100인 상태로 진행하였다. 따라서 스레드와 대기 용량풀을 늘릴 경우 더 성능이 좋은 결과값이 나올 것이다.

     

    최종 결론

    위와 같이 설정한 테스트 하에서, 서버 부하 수준이 중간 단계까지는 A와 B 방식에 유의미한 차이를 보기 힘들다.

    서버가 고부하 수준이 된다면 이때는 B 방법이 더 좋을 수 있다. 하지만 기본적으로 고부하 수준에서는 처리 속도보다 서버의 안정성이 더 중요하다 생각한다.

    따라서 안정성 면에서 더 좋고, 일반적인 서버 상황에서 성능이 비슷한 A방식을 쓰는 것으로 결정하였다,

     

    반응형

    댓글

Designed by Tistory.