yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆

[Python] locust 부하테스트 본문

개발/Python

[Python] locust 부하테스트

yehey 2023. 11. 11. 16:17

Today I Learned

: python locust를 이용한 부하 테스트를 진행하는 방법을 알아보았다.

배경

기존에 팀에서 웹 서버 개발에 사용하던 프레임워크는 장고와 플라스크였고 특히 flask 의 경우에는 내장 웹서버로 인해 한번에 한사람만 접근하기에 적합했고 이를 해결하기 위해 그동안 nginx + gunicorn으로 배포를 해왔다.

그런데 내가 맡은 프로젝트에서 golang 을 이용해서 서버를 개발했고 이를 배포하는 단계에서 golang 은 flask 처럼 gunicorn 과 nginx를 이용해서 배포하는 과정이 필수인지 알고 싶었다.

기존에는 gunicorn에서 workers를 추가하여 마치 n개의 서버가 하나의 서버처럼 돌아가도록 배포했다면 (추정)

golang 서버도 worker를 추가해야하는지 혹은 추가하지 않아도 자체적 go 루틴으로 처리되어 비동기처리 및 동시 실행이 가능한지 테스트 하고자 했다. 사실 구글링 결과로는 go 루틴으로 동시에 여러 요청 처리가 가능하다는 결과를 얻었지만, 그래도 직접 테스트를 통해서 확인할 필요가 있다고 생각해서 진행했다.

Contents

Locust?

python 기반의 성능 테스트 도구

python 기반으로 http 요청을 원하는 서버를 대상으로 보낼 수 있으며 복잡한 사용자 프로세스를 구현할 수도 있다. 그러나 간단한 요청만으로 복잡하지 않은 성능테스트를 진행할 수도 있다.

Locust를 선택한 이유: python을 사용했고 사용방법이 어렵지 않아서 성능 테스트를 간단히 진행하고 싶어서 선택했다.

Example / Practice

Locust 설치

pip3 install locust

Locust 테스트 코드 작성

locust 파일을 만들 디렉토리에 locustfile.py 파일을 생성한다. (파일 명은 달라도 됨)

import time
from locust import HttpUser, task, between

class QuickstartUser(HttpUser):
    wait_time = between(1, 5)

    @task
    def hello_world(self):
        self.client.get("/hello")
        self.client.get("/world")

    @task(3)
    def view_items(self):
        for item_id in range(10):
            self.client.get(f"/item?id={item_id}", name="/item")
            time.sleep(1)

    def on_start(self):
        self.client.post("/login", json={"username":"foo", "password":"bar"})

 

- HttpUser: HttpSession 인스턴스인 클라이언트 속성을 제공하며 테스트 대상 시스템에 HTTP 요청 을 할 때 사용, 테스트가 시작되면 Locust는 시뮬레이션 할 모든 사용자에 대해 해당 클래스 인스턴스를 생성하고 생성된 user는 고유한 green gevent thread (locust가 제공하는?)에서 실행한다.

- wait_time: 시뮬레이션 사용자의 task 가 종료된 후 대기 시간을 정의한다. 이를 적절히 사용하면 task 실행에서 지연이 발생한 상황을 시뮬레이션 할 수 있다.

- task (decorator): 실행되는 모든 user에 대해 locust가 greenlet (micro-thread)을 제공하고 @task 가 있는 method 중 하나를 임의로 선택해서 greenlet 내에서 실행하게 한다. @task(3) 과 같이 가중치를 줄 수 있는데 가중치를 주면 여러 task 중 실행되는 task의 비율을 조정할 수 있다 (ex. 위에서는 view_itemshello_world 함수보다 3배 정도 많이 선택되어 시뮬레이션 된다)

- self.client : self.client를 사용해서 http request를 진행하면 locust가 제공하는 logging 기능을 사용할 수 있다. (보통은 다들 이걸 이용해서 request를 보내는 듯 하다)

- on_start (on_stop) : 해당 이름을 가진 메소드를 추가할 경우 시뮬레이션 사용자를 생성할 때 (혹은 중단될 때) 마다 실행할 기능을 추가할 수 있다.

- User(class): 위의 예시 코드에는 없지만 HttpUser 클래스 말고 User 클래스를 쓰기도 한다. HttpUser가 User 중 하나고 Http request 기능을 제공하는 듯 (https://docs.locust.io/en/stable/writing-a-locustfile.html#user-class)

 

기타 유용하다고 생각하는 추가 기능

- Response Validation : https://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses

- http proxy setting: 사내 서비스 테스트라면 (사내 클라우드에 배포했다면) 보통 proxy가 설정되어있어서 접근이 제한되므로 추가로 프록시 설정을 하는 방법을 첨부한다. https://docs.locust.io/en/stable/writing-a-locustfile.html#http-proxy-settings

- task set: https://docs.locust.io/en/stable/tasksets.html#tasksets

locust 실행

일반적으로 locustfile.py 를 사용했다면 해당 파일 위치에서 locust만 사용해도 실행된다.

만약 파일 이름을 바꿨다면, -f 옵션을 주고 locust 테스트 파일을 입력해주면 된다.
locust
locust -f {customfilename}

locust 실행

실행하면 위와 같이 user 수와 user spawn rate (사용자 생성 속도 / 초당 사용자 수) 를 정하고 테스트를 진행할 Host 를 지정하고 테스트를 진행한다.

아래와 같은 테스트 결과를 얻을 수 있다.

(내가 했던 테스트는 사내 프로젝트 테스트로 공개가 불가능, 그치만 단순한 테스트여서 큰 분석은 필요하지 않았다)

Learned

python locust를 이용해서 사용자 수를 늘리고 서버 성능 테스트를 간단히 진행할 수 있었다.

golang 서버 배포 단계에서 별도로 workers 를 추가하지 않아도 go routine을 통해 비동기 처리와 동시 처리가 가능함을 눈으로 확인할 수 있었다.


What I Will Study

locust 외에 다른 성능 테스트 툴을 경험해보고 싶고, 지금은 동시처리가 가능한지 테스트만 진행했지만 조금 더 다양한 상황을 고려하며 테스트 코드를 짜보고 테스트를 진행해보고 싶다.

참조

https://etloveguitar.tistory.com/145
https://velog.io/@denhur62/locust%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%B6%80%ED%95%98-%ED%85%8C%EC%8A%A4%ED%8A%B8

'개발 > Python' 카테고리의 다른 글

python으로 스택 문제 시도  (0) 2021.01.21
윈도우 키로거  (0) 2020.11.15
Unix 패스워드 트래커  (0) 2020.11.15
포트 스캐너 (스레드, Nmap, optparse)  (0) 2020.10.11
python을 이용한 백도어 개발  (0) 2020.09.28
Comments