Locust·JMeter로 게임 서버 동시 접속자 한계 측정하는 로드 테스트 가이드

Locust와 JMeter로 게임 서버의 동시 접속자 한계를 재현하고 로그인·매치메이킹·게임 루프별 병목을 찾아 안전한 CCU와 확장 기준을 산정하는 실전 로드 테스트 방법을 정리합니다.

✓ 복사 완료!
챕터일반 가이드
난이도중급
상태● 검토 완료
대상 엔진
Engine Agnostic
최종 업데이트
Locust·JMeter로 게임 서버 동시 접속자 한계 측정하는 로드 테스트 가이드

게임 서버의 동시 접속자 한계는 CPU 사용률 하나로 판단할 수 없습니다. 로그인, 세션 생성, 매치메이킹, 실시간 패킷 처리, 데이터베이스 저장을 실제 이용 흐름에 가깝게 부하로 재현하고 p95 지연 시간·오류율·자원 포화 시점을 함께 관찰해야 합니다. Locust는 코드 기반 시나리오와 분산 실행에 JMeter는 HTTP API와 결과 리포트 검증에 적합하며 둘을 혼용해도 좋습니다.

게임 서버 동시 접속자 한계는 무엇으로 판단해야 할까?

동시 접속자(CCU, Concurrent Connected Users)는 특정 순간 서버에 연결된 활성 사용자 수입니다. 다만 모든 사용자가 같은 빈도로 요청하지 않으므로 CCU만으로 서버 부하를 설명하면 위험합니다. 실제 한계는 요청률, 패킷 크기, 데이터 저장량, 외부 의존성의 응답 시간에 따라 달라집니다.

안전 운영 기준은 보통 다음 조건을 동시에 만족하는 최대 부하로 정의합니다.

지표권장 판단 기준 예시의미
p95 응답 시간API SLA 이하사용자 95%가 허용 가능한 시간 안에 응답을 받는지
p99 응답 시간급격한 상승이 없는지소수 사용자에게 발생하는 긴 지연을 감지
오류율0.1~1% 이하 등 서비스 기준5xx, 타임아웃, 비정상 응답 비율
CPU·메모리지속 포화 전 여유 확보순간 피크가 아닌 장시간 안정성 확인
DB 연결·쿼리풀 고갈 및 슬로 쿼리 없음애플리케이션 밖의 병목 확인
게임 틱 지연목표 틱 간격 이내실시간 게임 루프의 품질 확인

초당 요청 수(RPS)는 다음처럼 근사할 수 있습니다.

RPS=CCU×사용자당 초당 평균 요청 수RPS = CCU \times 사용자당\ 초당\ 평균\ 요청\ 수

예를 들어 2,000 CCU가 사용자당 평균 초당 0.4회의 API 요청을 발생시키면 목표는 약 800 RPS입니다. 하지만 전투 시작이나 이벤트 보상 수령처럼 사용자가 한 행동에 집중되는 구간은 평균값보다 훨씬 큰 순간 피크를 별도로 테스트해야 합니다.

게임 서버 로드 테스트에서 로그인부터 매치메이킹과 전투 API까지 측정하는 흐름

로드 테스트 전에 무엇을 준비해야 할까?

1. 운영과 유사한 테스트 환경을 고정한다

가능하면 운영과 같은 서버 바이너리, 컨테이너 이미지, 데이터베이스 엔진 버전, 캐시 설정을 사용합니다. 테스트 환경의 인스턴스 크기나 DB 인덱스가 운영과 다르면 결과를 CCU 기준으로 그대로 옮길 수 없습니다.

개인정보와 실제 결제 데이터는 복제하지 않습니다. 테스트 계정, 더미 인벤토리, 독립된 결제 모의 서버를 준비하고 부하가 운영 시스템으로 전파되지 않도록 네트워크 경계를 확인합니다.

2. 사용자 행동을 요청 목록이 아니라 시나리오로 모델링한다

게임의 핵심 흐름을 비율과 대기 시간까지 포함해 정의합니다.

행동사용자 비율 예시주요 검증 대상
로그인·토큰 갱신100%인증 서버, 세션 저장소
로비 조회90%캐시 적중률, 프로필 조회
매치메이킹 신청35%큐 대기, 룸 생성
전투 행동 전송25%WebSocket 또는 UDP 처리, 틱 지연
보상 수령·저장20%트랜잭션, 락 경합

사용자 간 대기 시간(think time)을 넣지 않으면 모든 가상 사용자가 무한 루프로 요청을 보내 실제 게임보다 과도한 RPS를 만듭니다. 반대로 대기 시간을 지나치게 길게 잡으면 목표 CCU에서 필요한 부하가 생성되지 않습니다.

3. 관측 지표와 중단 기준을 먼저 정한다

테스트가 끝난 뒤에 로그를 찾기 시작하면 원인을 연결하기 어렵습니다. 애플리케이션 메트릭, 호스트 CPU·메모리, GC, DB 연결 풀, Redis 지연 시간, 로드밸런서 5xx를 같은 시간축에서 볼 수 있게 준비합니다.

중단 기준도 명시합니다. 예를 들어 오류율이 5%를 3분 넘게 유지하거나 데이터 정합성 오류가 발생하면 즉시 부하를 중지하고 원인을 보존합니다.

Locust로 게임 API 부하 시나리오를 어떻게 구현할까?

Locust는 Python 코드로 가상 사용자의 행동을 작성합니다. 아래 예시는 HTTP 기반 로그인, 로비 조회, 매치메이킹 요청을 비율로 섞는 최소 시나리오입니다. 실제 서비스에서는 테스트 전용 계정 발급 방식과 인증 헤더 규칙에 맞춰 수정해야 합니다.

from locust import HttpUser, between, task

class GameUser(HttpUser):
    wait_time = between(1, 3)

    def on_start(self):
        response = self.client.post(
            "/api/v1/auth/login",
            json={"accountId": "loadtest-user", "password": "test-password"},
            name="POST /auth/login",
        )
        response.raise_for_status()
        self.token = response.json()["accessToken"]
        self.client.headers.update({"Authorization": f"Bearer {self.token}"})

    @task(6)
    def get_lobby(self):
        self.client.get("/api/v1/lobby", name="GET /lobby")

    @task(3)
    def get_profile(self):
        self.client.get("/api/v1/profile", name="GET /profile")

    @task(1)
    def join_matchmaking(self):
        self.client.post("/api/v1/matchmaking/queue", name="POST /matchmaking/queue")

단일 부하 발생기로 목표 RPS를 만들기 어렵다면 Locust의 worker 모드로 여러 부하 발생기를 사용합니다. 이때 테스트 대상 서버뿐 아니라 부하 발생기 자체의 CPU, 네트워크 대역폭, 파일 디스크립터도 확인해야 합니다.

JMeter는 언제 사용하는 것이 좋은가?

JMeter는 HTTP 요청, CSV 기반 테스트 계정, 타이머, Assertion을 GUI에서 빠르게 구성하기 좋습니다. 특히 이미 QA 조직에 .jmx 테스트 플랜과 HTML 리포트 운영 방식이 있다면 API 회귀 성능 테스트에 효율적입니다.

상황LocustJMeter
복잡한 상태 전이·동적 데이터Python 코드로 유연하게 구현BeanShell·JSR223 설정이 필요할 수 있음
비개발자의 시나리오 편집코드 리뷰 필요GUI에서 구조 파악이 쉬움
대규모 분산 부하worker 구조로 확장 가능원격 엔진 또는 컨테이너 구성 필요
HTTP 결과 리포트웹 UI·외부 모니터링 연동HTML 리포트가 기본 제공됨

JMeter에서는 Thread Group의 사용자 수를 곧바로 CCU로 해석하지 않습니다. 루프 횟수와 타이머 설정에 따라 실제 활성 요청 수가 달라지므로 Summary Report의 Throughput, 90th·95th percentile, Error %를 서버 메트릭과 함께 봐야 합니다.

동시 접속자 한계를 측정하는 단계별 절차

1. 기준선 테스트를 실행한다

낮은 부하에서 API별 평균 응답 시간, p95, 오류율, DB 쿼리 수를 기록합니다. 이 기준선은 이후 지연이 어느 계층에서 증가했는지 판단하는 비교점입니다.

2. 단계적으로 CCU를 올린다

예를 들어 5분마다 100 CCU씩 증가시키고 각 단계에서 5~10분의 안정화 구간을 둡니다. 급격한 증가만 수행하면 자동 확장, 캐시 워밍업, 커넥션 풀 재생성의 영향을 구분하기 어렵습니다.

flowchart LR
    A[낮은 CCU 기준선] --> B[단계별 CCU 증가]
    B --> C{SLA와 오류율 충족?}
    C -- 예 --> D[다음 단계 유지 및 증가]
    C -- 아니오 --> E[포화 시점 기록]
    E --> F[메트릭·로그로 병목 분석]
    F --> G[개선 후 동일 시나리오 재시험]

3. 포화 시점과 안전 CCU를 분리한다

포화 시점은 p95가 급상승하거나 오류율이 증가하기 시작한 부하입니다. 안전 CCU는 그보다 낮게 잡아 장애, 배포, 이벤트 피크에 대응할 여유를 남긴 값입니다.

다음 식으로 여유율을 반영할 수 있습니다.

안전 CCU=측정된 안정 최대 CCU×(1−여유율)안전\ CCU = 측정된\ 안정\ 최대\ CCU \times (1 - 여유율)

측정된 안정 최대 CCU가 3,000이고 여유율을 30%로 정했다면 안전 CCU는 2,100입니다. 여유율은 트래픽 변동성, 자동 확장 시간, 장애 허용 수준에 따라 서비스별로 결정합니다.

4. 스파이크와 장시간 소크 테스트를 별도로 수행한다

램프업 테스트만 통과해도 출시 직후의 로그인 폭주를 견디는 것은 아닙니다. 목표 CCU의 1.5~2배 로그인 요청을 짧게 집중시키는 스파이크 테스트와 2시간 이상 일정 부하를 유지하는 소크 테스트를 따로 실행합니다. 소크 테스트에서는 메모리 누수, 커넥션 누수, 캐시 축출, 로그 디스크 증가가 주된 관찰 대상입니다.

p95가 높을 때 병목은 어떻게 찾을까?

응답 시간은 보통 네트워크, 애플리케이션 대기열, CPU, 데이터베이스, 외부 API가 합쳐진 결과입니다. 평균값이 정상이어도 p95와 p99만 악화된다면 락 경합, GC pause, 커넥션 풀 대기처럼 간헐적으로 큐가 쌓이는 문제를 의심합니다.

증상우선 확인할 원인개선 방향
CPU 90% 이상과 함께 p95 상승직렬화, 암호화, 게임 로직 과다 실행프로파일링 후 핫패스 최적화, 수평 확장
DB 연결 풀이 가득 참느린 쿼리, 트랜잭션 장기 점유인덱스·쿼리 개선, 풀 크기와 타임아웃 조정
Redis 지연 급증단일 키 핫스팟, 큰 값 직렬화키 분산, 값 크기 축소, 샤딩 검토
로그인만 5xx 증가인증 의존성, 토큰 서명 비용인증 서버 확장, 캐시, 요청 제한
전투 틱이 밀림단일 게임 룸 과부하, 이벤트 루프 블로킹룸 분산, 작업 분리, 틱 예산 측정

병목을 고쳤다면 같은 데이터셋, 같은 램프업, 같은 테스트 시간으로 재시험합니다. 시나리오를 동시에 바꾸면 개선 효과를 비교할 수 없습니다.

자주 묻는 질문 (FAQ)

CCU와 RPS 중 어느 지표가 더 중요한가?

둘 다 필요합니다. CCU는 연결 규모를 RPS는 처리량을 나타냅니다. 실시간 게임이라면 연결 수와 패킷 처리량, 틱 지연까지 함께 측정해야 합니다.

로드 테스트 결과가 운영보다 좋은 이유는 무엇인가?

테스트 데이터가 단순하거나 캐시가 이미 워밍업되어 있고 외부 결제·푸시·분석 시스템을 제외했을 가능성이 큽니다. 운영과의 차이를 문서화한 뒤 보정 테스트를 추가해야 합니다.

최대 CCU를 한 번 측정하면 끝인가?

아닙니다. 서버 코드, DB 스키마, SDK, 인프라 구성, 이벤트 콘텐츠가 바뀔 때마다 한계도 바뀝니다. 주요 배포 전에는 핵심 시나리오를 자동화해 성능 회귀를 확인하는 것이 좋습니다.

정리

게임 서버 로드 테스트의 목적은 숫자 하나를 크게 만드는 일이 아니라 서비스 품질이 무너지는 조건을 재현하고 안전한 운영 용량을 결정하는 일입니다. Locust 또는 JMeter로 실제 사용자 흐름을 만들고 단계적 부하·스파이크·소크 테스트를 분리해 실행하세요. p95 지연 시간, 오류율, DB와 캐시 포화, 게임 틱 지연을 함께 기록하면 동시 접속자 한계를 근거 있는 운영 기준으로 바꿀 수 있습니다.