1. 대규모 트래픽이 왜 중요한가?
최근 아이온2 출시 당시, 많은 유저가 동시 접속을 시도해 서버가 터지고, 스트리머들도 수 시간 동안 접속 대기 또는 반복 접속을 하다 포기하는 상황을 보게되었다 이 과정을 보며 느꼈던 점이 대규모 트래픽은 선택이 아니라 필수로써 한때 채용공고에서 “대규모 트래픽 경험”이 필수 자격으로 적힌 경우가 많았는데, 이제 와서 보니 그 이유를 확실히 체감하게 되었다.
그래서 나 역시 서버를 직접 운영할 개발자로서 "내가 서버를 운용하게 되었을 경우 비슷한 상황이 들이닥치면 어떻게 해야할까?" 라는 시뮬레이션을 해 보기로 했다.
2. 시나리오 설정
- 나는 특정 게임의 정보를 제공하는 사이트를 운영하고 있다.
- 해당 게임의 신규·복귀 유저 유입 시즌이 도래했다.
- 2025년 11월 26일 기준 게임 계정 수는 479,571개이며 신규유저가 유입되는것도 포함되는 상황을 생각한다면
최악의 경우 약 50만 번의 요청이 단시간에 몰릴 수도 있다. - 이 상황을 로컬/서버 환경에서 시뮬레이션하고 문제점있다면 해결 방법을 찾아서 반영해보자
3. 트래픽 부하 방법 조사
처음에는 가지고 있던 Postman Runner를 사용해 보려고 했지만, 다음과 같은 이유로 사용을 포기하였다.
- 동시 요청을 발생시키지 않음 (순차 요청)
- 응답을 동시에 받는 상황을 만들 수 없음
부하 테스트 도구로는 의미가 없다고 판단하였다.
많이 사용되는 부하 테스트 도구
- Locust (Python 기반, 추천)
→ 설치 간단, UI 제공, 동시유저·RPS 제어 가능, Python 사용해 시나리오 작성 가능 - k6 (JavaScript 기반)
- JMeter (전통적, 강력하지만 무거움)
- 그 외 nGrinder, SOAP UI등 존재
사용 도구 결론
Locust 사용
개발 환경이 Python이며 스크립트 작성이 매우 편리하기 때문에 최적이여서 내 상황에 가장 알맞다고 판단하였다.
4. Locust 설치 및 실행
설치
pip install locust
실행 명령어
python -m locust
locust 명령어가 정상적으로 실행이 되지 않을 경우
"Windows Store"에서 Python를 설치하여 사용 시 Scripts 경로가 PATH에 잡히지 않아 오류가 발생하여 python경로를 다시 확인하여 locust.exe파일을 찾아주어야 한다.(필자가 그러하였다.)
#locust.exe 위치 예시
C:\Users\user\AppData\Local\Packages\ PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\ LocalCache\local-packages\Python312\Scripts\locust
그 외 해결방법으로는 해당 경로를 환경 변수 PATH에 추가하여 명령어를 실행시켜주면 된다.
5. Locust 사용 방법
테스트 스크립트 만들기
프로젝트 폴더에 locustfile.py 생성
#locustfile.py
from locust import HttpUser, TaskSet, task, between
import random
class UserBehavior(TaskSet):
wait_time = between(1, 3)
@task(1)
def get_categories(self):
self.client.get("/api/categories/")#작성하신 api로 엔드포인트로 바꿔주세요
@task(1)
def get_contents(self):
self.client.get("/api/contents/")
@task(1)
def get_items(self):
self.client.get("/api/items/")
autocomplete_keyword=["파편", "수호", "파괴", "돌파석", "융화"]
@task(2)
def get_autocomplete(self):
item_keyword=random.choice(self.autocomplete_keyword)
self.client.get(f"/api/autocomplete/?item_keyword={item_keyword}")
search_keyword=["운명의 파편 주머니(소)", "운명의 파괴석", "운명의 수호석", "운명의 돌파석"]
@task(3)
def get_search(self):
search_keyword=random.choice(self.search_keyword)
self.client.get(f"/api/search/?search_keyword={search_keyword}")
@task(3)
def get_prices(self):
content_id= 27
self.client.get(f"/api/prices/?content_id={content_id}")
class LocustUser(HttpUser):
tasks = [UserBehavior]
- HttpUser = 가상의 사용자
- @task = 반복적으로 수행할 동작( @task(3)는 비중 3을 부여하는 의미입니다. )
결론적으로 유저 1명이 "UserBehavior"에 있는 task들을 실행시킨다는 의미
Locust 실행하기
웹 UI 접속 : http://localhost:8089
테스트 설정값 입력

주요 설정값
- Number of Users : 목표하는 동시 접속자 수)
- Spawn rate : 0명부터 초당 증가되는 유저 수
- Host : 테스트할 서버 주소(예시 : localhost:8000)
Start 버튼을 클릭하여 부하 테스트 시작
테스트 결과 분석

Locust에서 알려주는 내용
- RPS (초당 요청 수)
- Failures/s (초당 에러 수)
- P95 ( 전체 데이터셋을 순서대로 나열했을 때 하위 95%에 해당하는 값들을 포함하는 위치의 값 )
- P99 ( 전체 데이터의 99%가 해당 값보다 작거나 같다는 뜻)
- Users (요청하는 사용자 수)
해당사항을 참고하여 확인할 것
- 어느 시점부터 응답시간이 급격히 증가하는가
- 얼마나 많은 유저까지 안정적으로 처리 가능한가
- 어떤 API가 가장 느린가
- DB/서버 병목이 어디인가
6. 테스트 결과
Locust 테스트를 돌려본 결과
- 동시 접속자 20~30명 수준에서도 모든 API의 응답시간이 11~18초로 상승한다.
- RPS는 7~8로 유지되지만 동시 요청이 쌓여 응답 대기열이 밀리는 상황 발생.
결론
동시요청 20~30명 이상에서 처리 속도가 급격히 떨어지는 병목 발생하므로 해당상황에 있어 대부분 원인은 DB 커넥션 부족 + 인덱스 미사용 + 캐시 없음 라고 하니 해당사항들을 하나하나 도입하여 전, 후 처리속도를 비교해보자
'기타' 카테고리의 다른 글
| 대규모 트래픽 상황을 가정한 서버개선(index, redis) (0) | 2025.12.05 |
|---|