호딩클라우드

[Spring] gatling 성능테스트 with scouter 모니터링 본문

SpringBoot/꿀팁

[Spring] gatling 성능테스트 with scouter 모니터링

hoding-cloud 2024. 2. 26. 17:13

Gatling 설치

오픈소스 기반의 성능 측정 도구이며 내부적으로 Akka와 Netty를 사용하기 때문에 ngrinder와 Jmeter보다 적은 부담으로 더 많은 부하를 이용한 테스트를 진행할 수 있습니다.
 
홈페이지 : https://gatling.io/ 
학습페이지 : https://gatling.io/academy 
다운로드 : https://gatling.io/open-source/ 

 
다운로드 후 /bin 로가면 gatilng 실행파일과 recorder가 존재하는데 recorder는 시나리오 세팅을 도와주는 도구입니다.
 
예제 프로젝트로는 spring 리포지토리의 petclinic을 사용하겠습니다.
https://github.com/spring-projects/spring-petclinic
 
예제프로젝트를 다운로드한 뒤 실행시켜 주고 성능테스트를 하려는 페이지에 접속하면서 개발자도구에 네트워크 캡처를 진행해줍니다.
그 후 [개발자도구] - [Network] - [우클릭] - [Save all as HAR with content]를 눌러 HAR 파일을 다운로드해줍니다.

Har file 이란?

HTTP Archive format의 약자로 Json 형태의 파일로 네트워크 기록을 Debug 하기 위해 사용한다. Viewer를 통해 파일을 열어보면 아래 사진으로 확인할 수 있듯이 해당 유저가 Network Tab의 기록동안 어떤 일을 했는지 파악할 수 있다.

출처: https://devroach.tistory.com/125 [Rlog:티스토리]

즉, 특정 화면에서 사용되는 Request를 캡처한 json 형태의 파일입니다.

.. 생략 ..
"cache": {},
        "connection": "507062",
        "pageref": "page_2",
        "request": {
          "method": "GET",
          "url": "http://localhost:8080/owners?lastName=",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Accept",
.. 생략 ..

 
 

시나리오 스크립트 생성

gatiling은 Har file을 통해서 스크립트 초기 세팅을 할 수 있습니다.
 
1. Recorder mode를 HAR Converter로 지정해 줍니다.
2. 다운로드한 harfile을 Browse 해줍니다.
3. No static resources 버튼으로 static resource를 제거해 줍니다.
4. start 버튼으로 스크립트 파일을 생성해 줍니다.

Simulation information - inferHtmlResources 옵션을 켜게 되면 정적인 리소를 요청마다 받음으로 CDN을 사용할 경우 비용 및 자원낭비 문제로 이어질 수 있으니 서비스 개편, 서비스 최초 오픈 시에만 켜고 테스트하는 것을 권장한다고 합니다.

 
시나리오 파일은 gatling다운로드 폴더에 user-files/simulations에 생성됩니다.
 
생성된 파일 하단 부분에 ScenarioBuilder를 보면 HAR 파일을 기반으로 시나리오가 생성되어 있습니다.

 private ScenarioBuilder scn = scenario("RecordedSimulation")
    .exec(
      http("request_0")
        .get("/owners?lastName=")
        .headers(headers_0),
      http("request_1")
        .get("/webjars/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0")
        .headers(headers_1),
      pause(Duration.ofMillis(296)),
      http("request_2")
        .get("/github-markdown-css")
        .headers(headers_2)
        .check(status().is(404)),
      http("request_3")
        .get(uri4 + "/?ext_id=baecjmoceaobpnffgnlkloccenkoibbb&ext_width=318")
        .headers(headers_3),
      http("request_4")
        .get(uri1 + "/client")
        .headers(headers_4),
      http("request_5")
        .get(uri1 + "/style")
        .headers(headers_4),
      http("request_6")
        .get(uri1 + "/button?type=standard&shape=rectangular&theme=outline&text=continue_with&size=large&logo_alignment=center&width=318&client_id=630072318488-5jn6np2l4jknug91dehqarem7epqrua4.apps.googleusercontent.com&iframe_id=gsi_993525_871826&as=BY9fh2q7VMgNK2HCvGG4Ag")
        .headers(headers_6),
      http("request_7")
        .get(uri5)
        .headers(headers_7),
      pause(10),
      http("request_8")
        .post(uri2 + "?format=json&hasfast=true&authuser=0")
        .headers(headers_8)
        .formParam("[[1,null,null,null,null,null,null,null,null,null,[null,null,null,null,\"ko\",null,null,null,[[[\"Chromium\",\"122\"],[\"Not(A:Brand\",\"24\"],[\"Google Chrome\",\"122\"]],0,\"macOS\",\"13.4.1\",\"arm\",\"\",\"122.0.6261.57\"],[1,0,0,0,0]]],1112,[[\"1708928993737\",null,null,null,null,null,null,\"[\\\"BY9fh2q7VMgNK2HCvGG4Ag\\\",12,0,null,\\\"630072318488-5jn6np2l4jknug91dehqarem7epqrua4.apps.googleusercontent.com\\\",\\\"https://notegpt.io\\\",[2],null,null,null,null,null,null,4,null,null,null,[1,1,1,318,4,2,1]]\",null,null,12,null,null,null,-32400,null,null,null,null,null,1]],\"1708929003738\"]", "")
    );

  {
	  setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol);
  }

 
 
생성된 파일에 불필요한 Request를 정리해 줍니다.

..생략..
  private ScenarioBuilder scn = scenario("RecordedSimulation")
    .exec(
      http("request_0")
        .get("/owners?lastName=")
        .headers(headers_0)
    );

  {
	  setUp(scn.injectOpen(atOnceUsers(1))).protocols(httpProtocol);
  }
..생략..

 
기본적으로 gatiling은 일회성 부하를 주도록 설정해 줍니다.
단발성으로는 부하테스트를 하기 어렵기 때문에 스크립트를 수정해야 합니다.

용어 참고

Injection: Virtual User가 유입되는 방식을 결정합니다.


 
SetUp method 추가정보

더보기

SetUp method 

----------------------

  • nothingFor(duration): duration 만큼 그냥 대기
  • atOnceUsers(nbUsers) :사용자수만큼한번에수행
  • rampUsers(nbUsers).during(duration) : duration 동안 0~사용자 수 까지 증가
  • constantUsersPerSec(rate).during(duration) : duration동안 초당 rate명씩 추가
  • constantUsersPerSec(rate).during(duration) randomized() : duration동안 랜덤한 간격으로 rate명씩 추가
  • rampUsersPerSec(rate1).to(rate2).during(duration) : 초당 rate1명의 사용자에서 rate2명까지 일정한 간격으로 duration동안 증가 (10, 21, 33, 46, ...)
  • rampUsersPerSec(rate1).to(rate2).during(duration).randomized() : 초당 rate1명의 사용자를 rate2명까지 랜덤한 간격으로 duration동안 증가
  • stressPeakUsers(rate).during(duration): rate 명의 사용자를 duration동안 부하를 헤비사이드 계단 함수에 맞춰 증가

더 많은 정보 (Gatling document) 

 
아래 스크립트는 3초 동안 3명의 사용자수까지 증가(rampUser)시키고 60초 동안 시나리오대로 요청을 보내도록 설정합니다.

private ScenarioBuilder scn = scenario("RecordedSimulation")
		.during(60).on(
			exec(
				http("searchOwner")
					.get("/owners?lastName=")
					.headers(headers_0)
			)
		);


	{
		setUp(scn.injectOpen(rampUsers(3).during(3))).protocols(httpProtocol);
	}

 
 

스카우터 설치

다운로드 : https://github.com/scouter-project/scouter/releases
필자는 scouter-all-2.20.0.tar.gz을 다운로드하였습니다.

스카우터 구조

  • java agent -> 자바 모니터링 에이전트, jar 실행 시 옵션으로 attach 해줘야 합니다.
  • agent.host -> 서버 리소스 모니터링,
  • server(colleter) : agnet로부터 데이터수집, 파일가반의 수집서버이기 때문에 DB가 필요 없습니다.

pinpoint는 DB로 하둡를 사용해서 초기 세팅에 조금 더 번거로웠던 걸로 기억하는데 scouter에 경우 비교적 세팅이 수월하여 개인적으로 선호하는 APM입니다.
 
다운받은 폴더에 /scouter/server로 이동하여 startup.sh 파일에 원하는 버전의 jdk경로를 설정할 수 있습니다.
(scouter는 자바기반 오픈소스 입니다.)

/usr/libexec/java_home -V

사용가능한 jdk 버전과 경로를 확인하는 명령어
 
agent.host/host.sh 를 실행시켜주고 모니터링할 jar에 실행옵션으로 agent를 attach 해줍니다.

java -javaagent:{java agent 경로}/scouter.agent.jar -jar target/*.jar

 
스카우터의 초기세팅에 대한 자세한 정보는 아래 링크로 대체하겠습니다.
https://ta-starter.tistory.com/29

[Linux] Scouter 설치 및 구성

@ 사전작업 - Linux에 Tomcat이 설치되어 있는 환경 - Server, Agent, Client 모두 JDK 8 이상 필요 - Selinux disable # 지표 수신 서버(Collector) 작업 1. https://github.com/scouter-project/scouter/releases에서 scouter-all-2.10.0.t

ta-starter.tistory.com

 
scouter Client를 실행하고 Gatling을 통해 작성된 시나리오로 부하테스트를 실행해봅니다. 

 
부하를 받는 60초 동안은 TPS 및 다른 지표가 증가하는 것을 확인할 수 있습니다.
 

method 프로파일링

추가적으로 Xlog를 드래그하여 호출에 대한 상세정보를 확인할 수 있는데 이때 method 프로파일링을 추가해야 호출정보를 자세히 확인할 수 있습니다.
 

 
[was우클릭] - [configure] 를 통해 설정할 수도 있고 scouter/agent.java/conf/scouter.conf 파일을 수정해도 같은 효과를 얻을 수 있습니다.
해당 파일에 아래 옵션을 적으면 메소드 프로파일링이 활성화됩니다. (서버 재시작 필요)

[메소드 프로파일링 옵션]
hook_method_patterns=org.springframework.samples.petclinic.*.*

hook_method-patterns = ${package 표현식}
 
프로파일링이 활성화 되면 아래와 같이 노란색 글씨로 호출된 메소드 정보를 확인할 수 있습니다.
메소드 프로파일링에 대한 더 자세한 정보

 

Gatling Report

gatling 실행을 마친 뒤에 gatling/result 에 보고서 파일이 생성됩니다.

'SpringBoot > 꿀팁' 카테고리의 다른 글

Gradle plugin 이란? Gradle Custom Plugin 만들기  (1) 2024.02.15