티스토리 뷰

서버

스프링웹플럭스_4

Hilu 2021. 12. 17. 13:06

이번 들에서는 기존에 WebFlux 와 MVC 패턴을 이용한 NonBlocking, Blocking 테스트를 진행 하며 성능을 측정해 보도록 하겠습니다.

 

1. 테스트 tool 로는 K6 사용

공식홈페이지 : https://k6.io/

 

* k6 결과 값

  • vus — 활성 가상 사용자 수
  • vus_max — 테스트에 할당 된 최대 가상 사용자
  • iterations— default함수가 호출 된 총 횟수
  • iteration_duration— default함수 를 실행하는 데 걸린 총 시간
  • dropped_iterations— iterations시작할 수없는 수
  • data_received — 수신 된 데이터의 양
  • data_sent — 전송 된 데이터 양
  • checks — 성공적인 검사 비율 
  • http_reqs — k6에 의해 생성 된 총 요청
  • http_req_blocked — 요청을 시작하기 전에 사용 가능한 TCP 연결을 기다리는 데 소요 된 시간
  • http_req_connecting — TCP 연결 설정에 소요 된 시간
  • http_req_tls_handshaking — TLS 핸드 쉐이킹에 소요 된 시간
  • http_req_sending — 데이터 전송에 소요 된 시간
  • http_req_waiting — 원격 호스트의 응답을 기다리는 데 소요 된 시간
  • http_req_receiving — 데이터 수신에 소요 된 시간
  • http_req_duration— 요청에 대한 총 시간. http_req_sending+ http_req_waiting+를 기준으로 계산됩니다.http_req_receiving.

 

2. WebFlux VS MVC 단순 호출 테스트

=> 테스트 하려면 dependency 변경해 줘야함

implementation 'org.springframework.boot:spring-boot-starter-web'

<=>

implementation 'org.springframework.boot:spring-boot-starter-webflux'

 

WebFlux 

public Mono <ServerResponse> webfluxTest(ServerRequest req) {
        return ok().body(Flux.just("WebFlux Test", "OK!"), String.class);
}

 

MVC

@GetMapping("/nonWebFluxTest")
public String nonWebFluxTest() {
	return "Non WebFlux Test OK!";
}

 

Test.js

// test.js
import http from 'k6/http';
import { sleep } from 'k6';

export default function() {
  //http.get('http://localhost:8080/nonWebFluxTest'); // get MVC test
  http.get('http://localhost:8080/webFluxTest'); // get WebFlux test
}

 

2. WebFlux VS MVC 외부 호출 테스트

vus : 가상이용자수

duration : 테스트 시간

out : 결과 출력 포맷 (json, text, csv ...)

k6 run --vus 10 --duration 30s --out json=out.json test

WebFlux 테스트 결과

vus = 10, duration 30, webFlux

 

MVC 테스트

vus = 10, duration 30, MVC

 

두개의 API 서버를 구성하여 WebClient 로 호출 시에 성능 테스트

 

API 호출 부

 

MVC version (RestTamplate)

@Controller
public class HelloController {

    @Autowired
    private TestService testService;

    @ResponseBody
    @GetMapping("/nonWebFluxTest")
    public String nonWebFluxTest() {
        testService.callTestService();
        return "Non WebFlux Test OK!";
    }
}
@Service
public class TestService {

    @Autowired
    private ApiService apiService;

    public String callTestService() {
        try {
            String res = apiService.callAPI("http://localhost:9090/", HttpMethod.GET);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return "OK";
    }
}
@Service
public class ApiService {

    public String callAPI(String url, HttpMethod httpMethod) throws JsonProcessingException {

        HashMap<String, Object> result = new HashMap<String, Object>();

        String jsonInString = "";

        try {

            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setConnectTimeout(5000); //타임아웃 설정 5초
            factory.setReadTimeout(5000);//타임아웃 설정 5초
            RestTemplate restTemplate = new RestTemplate(factory);

            HttpHeaders header = new HttpHeaders();
            HttpEntity<?> entity = new HttpEntity<>(header);

            UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).build();

            //이 한줄의 코드로 API를 호출해 MAP타입으로 전달 받는다.
            ResponseEntity<Map> resultMap = restTemplate.exchange(uri.toString(), httpMethod, entity, Map.class);
            result.put("statusCode", resultMap.getStatusCodeValue()); //http status code를 확인
            result.put("header", resultMap.getHeaders()); //헤더 정보 확인
            result.put("body", resultMap.getBody()); //실제 데이터 정보 확인

            //데이터를 제대로 전달 받았는지 확인 string형태로 파싱해줌
            ObjectMapper mapper = new ObjectMapper();
            jsonInString = mapper.writeValueAsString(resultMap.getBody());

        } catch (HttpClientErrorException | HttpServerErrorException e) {
            result.put("statusCode", e.getRawStatusCode());
            result.put("body"  , e.getStatusText());
            System.out.println(e.toString());

        } catch (Exception e) {
            result.put("statusCode", "999");
            result.put("body"  , "excpetion오류");
            System.out.println(e.toString());
        }

        return jsonInString;
    }
}
@Controller
public class TestWebController {

    @ResponseBody
    @GetMapping
    public String pong() {
        return "pong";
    }
}

WebFlux version

@Service
public class WebFluxApiService {

    @Autowired
    private WebClient webClient;

    public Mono<String> get(String url) {
        return webClient
                .get()
                .uri(url)
                .retrieve()
                .bodyToMono(String.class)
                ;
    }
}
public Mono <ServerResponse> webfluxTest(ServerRequest req) {

	Mono<String> res = apiService.get("http://localhost:9090/");

	return ok().body(Flux.just("WebFlux Test", "OK!"), String.class);
}

호출 API 코드

@Controller
public class TestWebController {

    @ResponseBody
    @GetMapping
    public String pong() {
        return "pong";
    }
}

 

* 테스트 결과

 

MVC

vus = 10, duration 30, MVC

WebFlux

vus = 10, duration 30, WebFlux

 

iteratoin_duration 비교

mvc : avg 3.07ms

webFlux : avg 1.55ms

 

3. MVC => WebFlux 로 변경

https://pkgonan.github.io/2019/06/webflux-asynchronous-non-blocking-io-tuning

'서버' 카테고리의 다른 글

스프링웹플럭스_6  (0) 2022.02.14
스프링웹플럭스_5  (1) 2022.01.08
스프링웹플럭스_3  (0) 2021.11.24
스프링웹플럭스_2  (0) 2021.11.11
스프링웹플럭스_1  (0) 2021.11.10
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함