팀프로젝트에서는 Artillery로 부하 테스트를 진행했는데, Flask로 백엔드 서버를 만들었으니, Locust로 부하테스트를 해봐야겠다는 생각이 들었다.
아틸러리는 하나의 시나리오를 짜두고 실행하고나서 결과를 봤다면, 로커스트는 유저의 클래스를 만들고 테스트는 locust 대쉬보드에서 유연하게, 그리고 실시간으로 지켜볼 수 있는 차이가 있어 보인다. 아틸러리도 비슷한 기능을 제공할지 모르겠으나...
부하테스트는 할때마다 재밌다. 시험을 치는 느낌? 아마 리스크가 없는 서버니까 그런 거겠지만, 시뮬레이션 게임을 하는 재미와 비슷한 듯.
지난 글에서 만든 Synology Nas에 올린 백엔드 서버에 부하테스트를 진행했다.
시나리오는,
로그인 후 전체 thumbnail 요청을 1, 개별 사이트의 사진과 영상 요청을 10으로 1:10 비율과 1~5초 딜레이로 요청하는 유저 50명으로 했다.
코드는
import os
from locust import HttpUser, between, task
from dotenv import load_dotenv
import random
load_dotenv()
class UserBehavior(HttpUser):
host = os.getenv('SERVER')
# Simulated users will wait between 1 and 3 seconds between requests
wait_time = between(1, 5)
def on_start(self):
response = self.client.post(
"/login", json={"username": os.getenv('USER'), "password": os.getenv('PW')})
if response.status_code != 200:
print(
f"Login failed with status code: {response.status_code}, content: {response.text}")
return
try:
token = response.json()['access_token']
self.headers = {"Authorization": f"Bearer {token}"}
except Exception as e:
print(
f"Error decoding JSON: {e}. Response content: {response.text}")
@task(1)
def get_all_information(self):
self.client.get("/information/all", headers=self.headers)
@task(1)
def get_thumbnails(self):
response = self.client.get("/thumbnails", headers=self.headers)
try:
thumbnails = response.json()
for site in thumbnails:
self.client.get(f"/static/{site['url']}", headers=self.headers)
except Exception as e:
print(
f"Error decoding JSON for thumbnails: {e}. Response content: {response.text}")
@task(10)
def get_photo(self):
response = self.client.get(
"/images/Andong_GB_Education/2023-08-24", headers=self.headers)
photos = response.json()
random_photo = random.choice(photos)
self.client.get(
f"/images/Andong_GB_Education/2023-08-24/{random_photo.replace('.jpg','')}", headers=self.headers)
@task(10)
def get_video(self):
response = self.client.get(
"/video/Andong_GB_Education", headers=self.headers)
videos = response.json()
random_video = random.choice(videos)
self.client.get(
f"/video/Andong_GB_Education/{random_video}", headers=self.headers)
결과는 처-참
이라고 하기엔, NAS 서버의 성능....대비 얼마나 잘 나오는건지 알 수 없다. 1~5초에 한번씩 사진과 영상을 요청하는건 충분히 현실적인 사용량으로 생각되기 때문에 user 수를 조정하는 것이 우선 답으로 보인다.
DSM에 접속해보니, 22:30:34에 uwsgi가 메모리 부족으로 멈췄다는 로그도 하나 남아있다. ㅎㅎ...
10명으로 줄여봤다.
흠...
메모리 부족 로그 메일이 계속 날라온다.
1명으로 하면, 문제없이 되긴 한다.
그래도 좀 느리고, ssh로 접속해서 htop을 보면, 메모리가 100%가까이에서 머물러 있다.
5명까지도 failure는 없다. 응답은 느리지만
여기까지 우선 테스트 해본 결과, PIL로 thumbnail 메서드로 이미지를 메모리에 저장한 상태에서 바로 응답하는 방식때문에 메모리를 많이 차지하는 것으로 보인다. .. 메모리 사용을 줄이는 방법을 찾아봐야 하나? 메서드의 문제인가? ...
우선 해봤다는것에 의의를 두고, ... 개선할 수 있는 방향에 대해 좀 더 생각해봐야겠다.