영감을 (inspire) 주고픈 개발 블로그

[성능테스트 시리즈 - 1] 간편하게 백엔드 서버 성능 테스트 시스템 세팅하기: docker-compose를 성능 테스트를 쉽게 모니터링하는 방법 본문

개발/시스템 안정성 flow

[성능테스트 시리즈 - 1] 간편하게 백엔드 서버 성능 테스트 시스템 세팅하기: docker-compose를 성능 테스트를 쉽게 모니터링하는 방법

inspire12 2023. 12. 14. 16:18

성능테스트란?

서버 성능 테스트를 진행하면 서버가 어느 정도 부하에 대해 버틸 수 있는지 눈으로 확인해 볼 수 있다. 라이브 서버에 올리기 전 혹은 사용자가 몰릴 수 있는 이벤트를 진행할 때 서버에 리소스를 얼마나 부여해 줘야하는지 알려줄 수 있다. 

 

성능 테스트에 필요한 요소는 생각보다 간단하다.

  • 몇 명이 요청을 하는가
  • 각 인원이 몇 번을 요청하는가
  • 얼만큼 기간 동안 어느 정도 간격을 주고 요청을 줘야 하는가

여기서 몇 명이 접속(요청)했는가는 Threads(users)

한 명 당 몇 번식 요청하는가는 Loop Count 이다 

 

여기에 디테일하게 요청 주기나 딜레이 등을 추가로 설정 할 수 있다.

 

이 요청들을 뭉뚱그려서 흔히 "부하" 라고한다.

 

성능 테스트에 대한 추가적인 개념과 이론, 접근방법까지 적기엔 간편하게라는 글 컨셉에 어울리지 않아 아래 링크로 대체하겠다.


jmeter를 통해 부하주기

부하를 주는 툴은 다양하다. 이번 글에서는 jmeter를 사용해서 세팅을 구성했다.

처음 써보는 사람들에겐 UI가 있어야 세팅 구성하기가 편해 jmeter ui 를 우선 설치하는 걸 추가했다.

 

일단 OS 환경에 맞게 jmeter를 설치한다.

https://jmeter.apache.org/download_jmeter.cgi

 

Apache JMeter - Download Apache JMeter

Download Apache JMeter We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours) may not yet be ava

jmeter.apache.org

java 8버전이 설치되어야 jmeter를 실행할 수 있다.

  • windows일 경우 아래의 링크에서 zip 파일을 다운 후 압축을 풀고 jmeter.bat을 실행하면 된다.
  • mac 일 경우 brew install jmeter를 사용하면 설치할 수 있다

Thread group

jmter에서 Thread group 은 요청을 할 가상의 유저들을 설정하는 것이라 이해하면 된다.

그리고 thread group을 우클릭 후 HTTP Request를 추가해서 어떤 서버에 어떻게 요청을 보낼지를 설정할 수 있다.

 

Thread group의 각 요청 의미

  • Name : 테스트 이름이다. 당연하지만 안 중요하다.
  • Comments : 첨부할 설명이다. 당연하지만 안 중요하다.
  • Action to be taken after a Sampler error : 샘플러가 에러 시에 취할 행동이다. 사실 보통 Continue를 두면 에러와 무관하게 루프를 돌게 된다. 만약 다른 행동을 취하고 싶다면 해도 된다.
  • Number of Threads : 스레드를 동시에 몇 개 생성할지이다. 즉 동시에 몇 개의 트랜잭션을 실행시킬지이다. 이는 사람이 동시에 접속하는 효과를 낸다. 10명이서 동시에 접속하는 상황을 만들고 싶다면 10을 사용하면 된다.
  • Ramp-Up Period : 스레드를 Ramp-Up Period시간 동안 실행해라는 의미이다. 단 균등하게 시간을 나눠서 실행하려고 노력한다. 예를 들어 number of Threads가 10인데 Ramp-Up Period가 60이면 10개의 스레드가 6초 간격으로 동작하려고 한다. 근데 그렇게 안될 수도 있다. Loop Count : 스레드의 반복 횟수를 의미한다. 10이면 10번 반복한다. Forever에 체크하면 무한 반복한다.
  • Delay Thread creation until needed : 스레드의 생성을 필요할 때까지 기다린다. 체크를 해제하면 안 기다리고 날리는데 반응성은 더 좋아지긴 하는데 안정성을 위해서 체크해 두자.
  • Scheduler : 위의 모든 작업을 스케줄화 해서 할 수 있다.
  • Duration : Scheduler를 체크했을 때만 사용가능.
  • Thread Properties의 총작업을 하는 시간을 의미한다. 예를 들어 100초를 정하면 위의 작업을 딱 100초 동안 실행한다. 100초 안에 걸리는 작업이면 조기에 정지되지만 위의 작업이 100초를 넘어간다면 더 이상 실행하지 않고 멈춘다. Startup delay : 위의 작업을 실행하기 위한 유예기간을 의미한다. 스레드 그룹이 한개일때는 별 필요없지만 쓰레드 그룹을 여러 개 돌릴 때는 서로 차등을 줄 수 있다.

출처: https://kamang-it.tistory.com/399


grafana, influx db를 이용한 결과 시각화(report)

성능 테스트에서 또 중요한 건 결과를 깔끔하게 보여주는 것이다. 테스트툴은 많지만 결과를 시각화 방식이 도구에 종속적이며 결과를 원하는 대로 예쁘게 커스텀하기가 어렵다.

그래서 부하를 주는 건 기존의 jmeter 같은 테스트툴을 쓰고 결과를 보여주는 건 grafana dashboard를 통해 하는 방식으로 생각을 했다. 역시 이미 뛰어난 선배 개발자분들이 같은 아이디어로 설정해 놓은 것이 있어 가져다가 사용했다

참고한 글

실행

sh git clone https://github.com/testsmith-io/jmeter-influxdb-grafana-docker 
cd jmeter-influxdb-grafana-docker 
docker-compose up

대시보드 확인

localhost:3000/dashboards 접속, JMeter Dashboard 접속

 

jmeter 연동 (ui)

jmter 실행 > open > (clone 받은 프로젝트 내) jmeter-scripts/example.jmx 실행

 

 

부하테스트용 간단한 서버 실행 (예제) 

8080 포트로 spring 서버 실행

@RestController
public class LoadController {
    @GetMapping
    public ResponseEntity<Void> load(){
        int i = ThreadLocalRandom.current().nextInt(6);
        try {
            Thread.sleep(i * 100);
        } catch (InterruptedException e) {
            Thread.interrupted();
        }
        if (i  > 3) {
            return ResponseEntity.internalServerError().build();
        }
        return ResponseEntity.ok().build();
    }
}

 

jemter Http Request 설정 webserver 부분 수정 후 thread group 실행

 

 

grafana dashboard를 보면 applicaion 칸에 실행한 결과를 각 테스트별로 실시간으로 볼 수 있다.

 

etc..

docker-compose.yml 설정 보기

dashboards를 설정한 docker-compose.yml를 보면 influxdb와 grafana 설정을 볼 수 있다. jmeter를 실행하면 8086 포트의 db에 저장되며 grafana는 3000 포트로 시작하는 걸 볼 수 있다. 만약 3000 포트를 쓰고 있다면 해당 3000:3000에서 앞의 3000을 변경해 주면 된다

version: '3.5'
services:
  influxdb:
    image: influxdb:1.8.10-alpine
    ports:
     - "8086:8086"
     - 25826:25826/udp
    networks:
     - grafana-influxdb-network
    volumes:
     - ./influxdb/influx_init.iql:/docker-entrypoint-initdb.d/influx_init.iql
     - ./influxdb/types.db:/usr/share/collectd/types.db:ro
     - ./influxdb/data:/var/lib/influxdb
     - ./influxdb/config/:/etc/influxdb/

  grafana:
    image: grafana/grafana:8.5.2
    depends_on:
      - influxdb
    volumes:
      - ./grafana/provisioning/:/etc/grafana/provisioning/
    ports:
      - "3000:3000"
    env_file:
      - 'grafana.env'
    links:
      - influxdb
    networks:
      - grafana-influxdb-network

networks:
  grafana-influxdb-network:
    driver: bridge