최근 교육용 게임 콘텐츠에 사용되는 웹소켓 서버를 담당하며 성능테스트와 모니터링 서버 구축, 테스트 시나리오 설계, 결과 보고서 작성까지 전 과정을 맡게 되었다.
처음에는 단순히 “부하를 주고 버티는지 확인하는 작업”이라고 생각했다.
하지만 실제로 경험해보니 성능테스트는 전혀 다른 의미를 갖고 있었다.
이 글에서는 제가 직접 겪으며 깨달은 점을 정리해보고자 한다.
처음하는 성능테스트와 모니터링
성능테스트와 모니터링은 모두 처음이었다.
그래서 가장 먼저 개념부터 정리했다. Load, Stress, Spike 테스트의 목적과 차이를 조사했고, 프로젝트에 맞는 구조를 그려보았다.
당시 제 생각은 단순했다.
성능테스트는 목표 동시 접속 수까지 올려보는 테스트이다.
또는 서버가 언제 터지는지 보는 실험이다.
하지만 이 생각은 절반만 맞았다.
숫자는 결과일 뿐, 설명이 아니었다.
성능테스트 실행계획 작성하기
무작정 부하를 발생시키지 않고, 실행계획부터 수립했다.
- 고객사 요구조건 기반 목표 동접 정의
- 테스트 유형별 시나리오 설계
- 관측할 메트릭과 판단 기준 정의
이 과정에서 중요한 사실을 깨달았다.
성능테스트는 “부하를 주는 작업”이 아니라 “가설을 세우는 작업”이다.
어떤 상황에서 어떤 결과가 나와야 정상인지 정의하지 않으면 테스트는 의미를 갖지 못한다.
부하 발생 시나리오: 숫자가 아니라 질문을 설계하다
웹소켓 서버의 특성상 단순 연결 유지 테스트로는 충분하지 않았다.
- 점진적 증가 (Load)
- 한계 탐색 (Stress)
- 급격한 폭주 (Spike)
특히 재접속 로직과 이벤트 처리 지연이 중요한 요소였다.
예를 들어 목표가 10,000명 동시 접속이라고 가정한다.
6,000명에서 멈춘다면 문제는 “왜 10,000명이 안 됐는가”가 아니다.
문제는 다음과 같다.
- 4,000명은 어디에서 실패했는가?
- 연결 단계 중 어느 구간에서 병목이 발생했는가?
- 재접속은 몇 % 발생했는가?
- 재접속 성공률은 얼마인가?
- 재시도 간격은 적절했는가?
- CPU/Memory는 어떤 패턴을 보였는가?
이 질문에 답하지 못하면 동접 수는 의미 없는 숫자에 불과했다.
이 시점에서 성능테스트의 정의가 바뀌었다.
성능테스트는 수치를 맞추는 작업이 아니라, 시스템이 무너지는 지점을 설명하는 작업이다.
메트릭 수집 계획: 관측이 없으면 분석도 없다
성능을 논하려면 관측이 선행되어야 한다.
그래서 테스트 이전에 어떤 메트릭을 수집할지 먼저 정의했다.
- 활성 소켓 연결 수
- 연결 성공/실패 비율
- 재접속 시도 및 성공률
- CPU, Memory 사용량
- 이벤트 처리 지연 시간
코드를 수정해 필요한 메트릭을 노출했다.
이 단계에서는 모든 것이 정돈된 것처럼 보였다.
서버 이중화와 메트릭 수집 구조의 재설계
운영 서버가 이중화되면서 문제가 발생했다.
Prometheus가 로드밸런서를 통해 scrape하는 구조에서는 인스턴스 단위 메트릭이 왜곡될 수 있었다. 특정 서버의 지표가 누락되거나 분산되었다.
이 문제는 단순 설정 문제가 아니었다.
“수집 방식 자체”를 다시 고민해야 했다.
Pull에서 Push로의 전환
Pushgateway를 도입해서 수집 구조를 변경했다.
- 각 서버가 Pushgateway로 메트릭 전송
- Prometheus는 Pushgateway만 scrape
- 인스턴스 라벨링을 명확히 정의
이 구조 변경 이후 인스턴스 단위 분석이 가능해졌다.
이 경험을 통해 알게 되었다.
모니터링은 도구의 문제가 아니라 구조의 문제이다.
수치로 패턴을 읽기 시작했다
성능테스트를 진행하면서 단순 결과 확인을 넘어서 패턴을 보기 시작했다.
- 특정 동접 구간에서 연결 실패 급증
- 재접속 요청 폭주
- RSS 지속 증가
- CPU보다 메모리에서 먼저 나타난 이상 징후
이제는 “안 된다”가 아니라 “왜 여기서 무너졌는가”를 설명해야 했다.
성능테스트는 이벤트가 아니라 분석 과정이었다.
로그 체계화: 원인 추적의 시작점
기존에는 로그가 파일 단위로 분리되어 있었다.
- error
- rejections
- exceptions
- info
분석 시 파일을 각각 확인해야 했다.
그래서 Loki를 연동하고 로그를 중앙화했다.
서버, 클러스터, 서비스 단위 라벨을 설계해서 시간축 기준 원인 추적이 가능하도록 구조화했다.
이후에는 “문제가 있었다”가 아니라 “어느 시점, 어느 인스턴스, 어떤 이벤트에서 시작되었다”고 말할 수 있게 되었다.
결과보고서: 테스트는 여기서 완성된다
성능테스트는 실행으로 끝나지 않다.
보고서 작성 단계에서 비로소 완성된다.
정해진 양식은 없었다.
그래서 다음을 기준으로 정리했다.
- 어떤 시나리오에서
- 어떤 문제가 발생했고
- 어떤 지표를 근거로 분석했으며
- 어떤 개선 방향을 제시하는가
이 과정에서 빠진 지표도 발견했다.
설명이 부족한 부분도 있었다.
하지만 가설을 세우고 근거를 제시하며 “설명 가능한 결과”로 정리했다.
마무리: 성능테스트의 정의가 바뀌었다
처음에는 성능테스트를 숫자 확인 작업이라고 생각했다.
이제는 이렇게 정의한다.
성능테스트는 서버의 한계를 찾는 작업이 아니라, 한계가 시작되는 지점을 설명하는 작업이다.
성능테스트를 진행하면서 절대 단기간에 할 수 있는 작업이 아님을 알았다. 목표와 시나리오, 관측 기준이 명확히 정의된 후 진행해야 추가 수정이 없고, 성능테스트 이후 결과 보고서 작성 단계에서 메트릭이 추가되거나 하는 일이 발생하기 때문이다.
다음 프로젝트에서 성능테스트를 다시 담당하게 된다면, 이번에 겪고 느꼈던 아쉬운 부분과 잘 했던 부분을 체크리스트로 만들어 준비하고, 관측 구조부터 먼저 설계할 것이다.
이번 경험이 단순 테스트 수행이 아닌, 시스템을 이해하는 방법을 배우는 유익한 과정이었다.