선착순 쿠폰 서비스를 기획, 구현 중이다. 하지만 혼자서 접속을 해서 동시 접속자의 상황을 재연하기에는 무리가 있다. 마우스를 잡은 손은 하나니까! 그렇기에 고민하던 중, Locust 에 대해 알게 되었고 동시 접속을 테스트하기에 적합할 뿐만 아니라 성능에 대한 테스트도 가능하다는 것을 알게 되었다. 지금부터 알아보자.
🟢 Locust
Locust는 Python으로 작성된 오픈소스 부하테스트 도구이다. Locsut를 사용하면 분산 시스템에서 여러 사용자를 시뮬레이션하여 웹 애플리케이션의 성능을 측정할 수 있다. 또한 매우 사용하기 쉽고 확장성이 뛰어나며, 사용자 시나리오를 코드로 작성할 수 있어 유연성이 높고, 대시보드를 통해 실시간으로 테스트 결과를 모니터링 할 수 있어 테스트 중에 성능 이슈를 발견하고 조치할 수 있다.
docker-compose 를 이용해 구현해 보고자 했다. worker 는 Locust 테스트를 수행하는 역할을 담당하며, master는 Locust 웹 인터페이스를 제공하고, worker에서 수행한 결과를 수집하여 테스트 결과를 종합하고, 그 결과를 웹 인터페이스를 통해 제공한다.
Locust with Docker-compose
load-test 라는 디렉토리를 형성해 그 안에 구성을 해보겠다. 먼저 테스트 파일을 생성한다. locust 는 python 기반의 오픈소스이기 때문에 python 으로 작성해야 한다.
[locustfile-hello.py]
from locust import task, FastHttpUser
class HelloWorld(FastHttpUser):
connection_timeout = 10.0
network_timeout = 10.0
@task
def hello(self):
self.client.get("/hello")
..
..
[HelloController]
@RestController
public class HelloController {
// 부하 테스트
@GetMapping("/hello")
public String hello() {
return "hello!";
}
}
FastHttpUser는 Locust의 사용자 모델 중 하나로, 더 빠르고 경량화된 HTTP 클라이언트를 사용하는 것이 특징이다.
connection_timeout 은 클라이언트가 서버에 연결을 시도할 때 최대 대기 시간을 의미하며, network_timeout 은 클라이언트가 서버로부터 응답을 받기 위해 대기하는 최대 시간을 의미한다. 또한 task 데코레이터를 사용하여 다음 메서드를 Locust 작업으로 등록한다.
docker-compose 아키텍처
# Docker Compose 파일 버전, 버전 3.7을 사용
version: '3.7'
# 이 파일에서 정의하는 서비스의 목록
services:
# 마스터 서비스
master:
# 사용할 이미지는 locustio/locust
image: locustio/locust
ports:
# 호스트의 8089 포트와 컨테이너의 8089 포트를 연결 (Locust의 웹 인터페이스 포트)
- "8089:8089"
volumes:
# 현재 디렉토리(.)를 컨테이너의 /mnt/locust 경로에 마운트 (Locust 스크립트 포함)
- ./:/mnt/locust
command: -f /mnt/locust/locustfile-hello.py --master -H http://host.docker.internal:8080
# 컨테이너가 시작될 때 실행할 커맨드
# locustfile-hello.py 파일을 사용, 마스터 모드로 실행, 테스트 대상 호스트는 host.docker.internal:8080
# 워커 서비스
worker:
# 마찬가지로 locustio/locust 이미지 사용
image: locustio/locust
volumes:
# 마스터와 동일하게 현재 디렉토리를 컨테이너에 마운트
- ./:/mnt/locust
command: -f /mnt/locust/locustfile-hello.py --worker --master-host master
# 컨테이너가 시작될 때 실행할 커맨드
# locustfile-hello.py 파일을 사용, 워커 모드로 실행, 마스터 호스트의 이름을 'master'로 지정 (Docker Compose는 서비스 이름을 호스트 이름으로 사용)
docker-compose 에 더욱 익숙해지고 locust 에 대한 내용을 깊이 이해하고 싶어 자세한 내용을 모두 주석으로 달아두었다.
여기까지 했으면 모든 준비는 끝났다. 도커를 생성하고 바로 테스트를 진행하자!
✅ Locust Connect
docker-compose 를 아래의 명령어로 실행하면 load-test 에 master 와 worker 가 정상적으로 실행된 것을 확인할 수 있다.
docker-compose up -d
그 후에 localhost 의 8089 포트로 접속하면 아래와 같은 페이지를 확인할 수 있다. 이 페이지를 통해 command 에 작성된 파일을 기반으로 docker locust 를 호스팅하고 그에 대한 테스트를 진행한다.
🔻Number of users
- 생성할 가상 사용자의 최대 수
🔻Ramp up
- 초당 생성할 가상 사용자의 수
🔻Host
요청받을 대상 주소
나는 Number of Users 의 수를 1,000 으로 하고, Ramp up 의 수를 100으로 설정했다. 즉, 초당 100명씩 최대 1,000명의 가상 사용자를 대상으로 테스트를 진행하기로 했다.
하지만 MySQL 에 CPU 가 7,80% 까지 올라가고 정상적인 테스트가 진행되지 않은 것으로 보였다. 이게 정상적인 테스트라고 볼 수 있는가 ?
이는 한대의 worker 로 초당 100명의 접속을 감당하기에 무리인 것으로 보여, worker 의 수를 증가시켜주기로 했다.
docker-compose up -d --scale worker=3
Docker 와 Locust 내부, workder 가 3대로 증가한 모습
이를 통해 MySQL 의 부하를 해결하고 정상적인 테스트 환경을 구축할 수 있었다.
*️⃣글을 마치며
이번 글을 통해 서버 성능 테스트, 스트레스 테스트의 맛을 본 것 같다. 이번 글을 기반으로 좀 더 다양한 테스트를 진행하며 습득하는 지식에 보람을 느끼며 개발의 재미를 느껴가고 있다. 다음 포스팅엔 실제로 선착순 기능에 대한 테스트를 다르며 생기는 트러블 슈팅에 대한 과정을 담아보겠다 : )