성능 테스팅 (Performance Testing) - 부하, 스트레스, 스파이크, 인듀어런스 테스트
핵심 인사이트 (3줄 요약)
- 본질: 성능 테스팅(Performance Testing)은 시스템이 단순히 '에러 없이 돌아가느냐(기능)'를 넘어, 수많은 유저가 동시에 접속하는 실제 운영 환경에서도 **'약속된 응답 시간(Latency)과 처리량(Throughput)을 유지하며 터지지 않고 버티느냐(비기능)'**를 시뮬레이션하는 극한의 인프라 검증 기법이다.
- 가치: 아무리 화려한 기능(결제, 예매)을 짰어도 1만 명이 동시 접속했을 때 서버가 멈추면 매출은 0원이다. 성능 테스트는 병목 구간(DB 락, 메모리 누수, 네트워크 지연)을 사전에 발라내고, 클라우드 자원의 최적 스케일링 임계치(Threshold)를 수학적으로 산출하여 블랙프라이데이 같은 트래픽 쓰나미로부터 비즈니스 생존을 보장한다.
- 융합: 실무에서는 단순히 JMeter나 LoadRunner로 트래픽을 쏘는 것을 넘어, APM(Application Performance Management, 예: 제니퍼, 스카우터) 모니터링 툴과 융합되어, 가상 트래픽(Virtual User)이 들어올 때 **어느 코드 라인(SQL)에서 몇 초가 걸리는지를 프로파일링(Profiling)**하는 거시적 품질 관리 아키텍처로 작동한다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
-
개념: 성능 테스팅은 4가지의 강력한 서브 무기로 나뉜다. ① 부하(Load): 평소 예상되는 최대 유저(1,000명)를 넣어놓고 시스템이 정상 작동하는지 보는 '기본 체력 검사'. ② 스트레스(Stress): 한계치(3,000명) 이상의 미친 트래픽을 때려 넣고, 서버가 언제/어떻게 부서지는지(Crash Point) 확인하는 '한계 돌파 검사'. ③ 스파이크(Spike): 10명에서 갑자기 10,000명으로 1초 만에 수직 상승시켰다가 빼는 '수강 신청/티켓 예매 충격 검사'. ④ 인듀어런스/내구성(Endurance/Soak): 적당한 부하(500명)를 3일 밤낮으로 끄지 않고 계속 줘서, 서서히 램(RAM)이 새는 메모리 누수(Memory Leak)를 잡는 '마라톤 검사'.
-
필요성: 명절 기차표 예매 사이트가 열렸다. 개발망에서 혼자 테스트할 때는 0.1초 만에 예매가 잘 됐다. 하지만 10만 명이 동시에 클릭 버튼을 누른 순간, 서버 CPU가 100%를 치고 DB 커넥션 풀(Connection Pool)이 말라붙으며 화면이 뻗었다. 이런 대장애가 터지면 뉴스를 타고 기업 이미지가 산산조각 난다. 소프트웨어의 기능(Logic)은 1명일 때와 1만 명일 때 완전히 다르게 작동한다(동시성 이슈, 데드락). 이 재앙을 사전에 똑같이 모의실험(Simulation)하여 인프라를 증설(Scale-out)하고 튜닝하기 위해 성능 테스트가 절대적으로 필요하다.
-
💡 비유: 자동차가 고속도로를 달릴 준비가 되었는지 검사하는 방법입니다.
- 기능 테스트: 시동 켜고, 핸들 돌리고, 브레이크 밟아서 차가 잘 서는지(동작) 봅니다.
- 부하 테스트 (Load): 트렁크에 규정된 짐(500kg)을 다 싣고 시속 100km로 정상적으로 달릴 수 있는지 봅니다.
- 스트레스 테스트 (Stress): 트렁크에 짐 2톤(한계 초과)을 싣고 풀악셀을 밟아서, 바퀴가 먼저 터지는지 엔진이 먼저 터지는지(약점) 봅니다.
- 스파이크 테스트 (Spike): 차를 타고 가다 갑자기 시속 200km로 1초 만에 급가속할 때 엔진이 꺼지는지 봅니다.
- 인듀어런스 테스트 (Endurance): 에어컨과 오디오를 다 켜고 부산까지 10시간 동안 한 번도 안 쉬고 달렸을 때, 나사나 엔진오일이 서서히 새어 나오지(Memory Leak) 않는지 봅니다.
-
등장 배경 및 발전 과정:
- 초기 수동 테스트 시대: 사람들이 모여서 일제히 F5(새로고침)를 연타하던 무식한 시대.
- 가상 유저(VUser) 자동화 도구 도입: HP LoadRunner, Apache JMeter 등 하나의 PC에서 수천 명의 가짜 쓰레드를 만들어 트래픽을 쏘는 상용/오픈소스 툴이 표준이 됨.
- 클라우드 스케일의 성능 테스트 (현재): K6, Gatling, nGrinder 등이 결합하여, 단순히 패킷을 쏘는 걸 넘어 클라우드의 오토스케일링(Auto-scaling) 임계점이 제때 터지는지를 검증하는 인프라 융합 테스팅으로 진화함.
-
📢 섹션 요약 비유: 평소 잔잔하던 댐(서버)이 잘 버티는지 보기 위해, 일부러 상류에서 홍수 물(가상 트래픽)을 한계치까지 콸콸 쏟아부어 보면서, 댐의 어느 시멘트 벽(병목 코드)에 제일 먼저 금이 가는지 목숨 걸고 찾아내는 최악의 모의 재난 훈련입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
성능 테스트의 4대 핵심 지표 (Metrics)
"서버가 느리다"라는 추상적 문장을 버리고, 성능 엔지니어는 4개의 숫자로 통신한다.
┌───────────────────────────────────────────────────────────────┐
│ 성능 테스팅 아키텍처의 4대 심장 (Performance Metrics) │
├───────────────────────────────────────────────────────────────┤
│ │
│ [ 1. TPS (Throughput) - 처리량 ] ◀── 제일 중요함! │
│ - Transaction Per Second. "초당 몇 명의 요청을 처리해 냈는가?" │
│ - 시스템의 '절대적 힘(근력)'을 나타냄. (예: 목표 TPS 10,000) │
│ │
│ [ 2. 응답 시간 (Response Time / Latency) ] │
│ - 유저가 '클릭'하고 화면이 바뀔 때까지 걸린 핑퐁 시간. │
│ - "99%의 유저가 1초 이내에 응답을 받았다(P99 Latency)." │
│ │
│ [ 3. VUser (Virtual User) - 동시 접속자 수 ] │
│ - JMeter가 쏘아대는 가짜 유저 쓰레드(Thread)의 개수. │
│ - 주의: 동접자(VUser)가 1만 명이라고 TPS가 1만이 아님! (사람은 클릭하고 │
│ 3초간 글을 읽으며 쉬기 때문 ─▶ Think Time) │
│ │
│ [ 4. 리소스 사용률 (Resource Utilization) ] │
│ - 테스트 중 서버의 CPU, RAM, Network I/O가 몇 %로 타오르고 있는가? │
│ │
│ ▶ (성능 병목의 공식): VUser를 1,000 ─▶ 2,000 ─▶ 3,000으로 늘렸을 때, │
│ 초반엔 TPS도 같이 좍좍 오르다가 어느 순간(임계점) VUser를 아무리 늘려도│
│ TPS는 안 오르고 응답 시간(Latency)만 미친 듯이 수직 상승한다! │
│ ─▶ 바로 이 지점이 시스템의 최대 한계점(Saturation Point)이다! │
└───────────────────────────────────────────────────────────────┘
[다이어그램 해설] 초보 성능 테스터들이 가장 착각하는 것이 "가상 유저(VUser)를 1만 명으로 세팅하고 돌리면, 초당 1만 건(TPS)의 부하가 가겠지?"라는 생각이다. 유저는 컴퓨터가 아니다. 화면을 클릭한 뒤 기사를 읽는 '생각하는 시간(Think Time)'이 있다. 만약 1번 클릭하고 9초를 쉰다면, 이 유저가 발생시키는 초당 트래픽은 0.1건이다. 따라서 VUser 1만 명을 쏴도 실제 부하(TPS)는 1,000밖에 안 걸린다. 진짜 프로 성능 엔지니어는 이 Think Time과 Pacing(유저 간격)을 수학적인 리틀의 법칙(Little's Law: L = λW)에 대입하여 실제 유저의 행동 패턴과 소름 돋게 똑같은 부하 스크립트를 설계해 낸다.
부하(Load) vs 스트레스(Stress) vs 스파이크(Spike) vs 인듀어런스(Soak)
| 테스트 종류 | 트래픽 투입 시나리오 (그래프 모양) | 탐지하려는 진짜 목적 (Target Bug) |
|---|---|---|
| 부하 (Load) | 계단식으로 서서히 올리다, 목표치(100%)에서 평평하게 유지 | 시스템이 약속된(SLA) 응답 시간 1초를 무사히 유지하는지 평가지표 획득. |
| 스트레스 (Stress) | 목표치 100%를 뚫고, 200%, 300%까지 미친 듯이 무한 상승 | 시스템이 결국 죽을 때, DB가 먼저 죽는지 웹서버가 죽는지(약점) 파악하고 에러 메시지를 잘 뱉는지 방어력 검증. |
| 스파이크 (Spike) | 평온하다가 갑자기 수직의 송곳(Spike)처럼 1,000% 트래픽 1초 만에 타격 | 대학교 수강 신청 등 돌발 상황에서 튕겼던 서버가, 스파이크가 지나가면 스스로 정상으로 되돌아오는지(회복력) 검사. |
| 인듀어런스 (Endurance) | 50%의 적당한 부하를 주고, 1주일 내내 끄지 않고 길고 얇게 달림 | 이틀쯤 돌았을 때 서서히 램(RAM) 용량이 차오르는 메모리 누수(Memory Leak)와 자원 고갈 버그를 잡아내는 유일한 기술. |
Ⅲ. 실무 적용 및 기술사적 판단
실무 시나리오
-
시나리오 — 티켓 예매 사이트의 DB 락(Lock)에 의한 스트레스 붕괴: 아이돌 콘서트 예매 사이트를 만들었다. 평소 유저 100명이 접속할 땐 너무 빨랐다. 성능 테스트(JMeter)를 켜서 스트레스(Stress) 테스트로 1만 명(VUser)을 동시에 "예매 버튼"을 클릭하게 때려 넣었다. 갑자기 WAS(스프링 부트) 서버의 CPU는 5%밖에 안 돌고 있는데, 예매 성공은 아무도 안 되고 응답 시간(Latency)이 30초를 넘어갔다.
- 판단: 전형적인 백엔드의 DB 커넥션 풀(Connection Pool) 고갈 및 락(Lock) 병목이다.
- 해결책: WAS(웹서버)가 노는 이유는 뒤에 있는 DB 서버가 응답을 안 줘서 목 빠지게 기다리고(Wait) 있기 때문이다. 1만 명이 동시에
UPDATE 좌석 SET 상태='완료'쿼리를 치려다 보니, 오라클 DB 안에 '배타적 락(Exclusive Lock)'이 거미줄처럼 꼬인 것이다. 아키텍트는 즉시 쿼리 로직을 분산시키고, 대기 큐(Message Queue, Redis)를 도입해 1만 명의 클릭을 순차적으로 1초에 1,000건씩만 DB에 던져주도록 비동기 완충(Buffer) 아키텍처로 재설계한 뒤 다시 부하 테스트를 통과시켜야 한다.
-
시나리오 — 인듀어런스(Soak) 테스트가 잡아낸 치명적 OOM (Out Of Memory): 글로벌 금융 결제 시스템 납품 1주일 전. 부하(Load) 테스트로 3시간을 빡세게 돌렸는데 서버가 완벽하게 버텼다. 감리단이 마지막으로 인듀어런스(Endurance) 테스트를 걸고 퇴근했다. 다음 날 아침 출근해 보니 새벽 4시경 서버가
java.lang.OutOfMemoryError를 뿜으며 뻗어있었다.- 판단: 3시간짜리 부하 테스트로는 절대 잡을 수 없는 은밀한 자원 누수(Resource Leak) 버그다. 자바(Java) 코드에서 해제되지 않은 객체(List 등)가 가비지 컬렉터(GC)를 피해 메모리에 차곡차곡 쌓인 것이다.
- 해결책: 즉각 **APM 도구(제니퍼 등)**와 **힙 덤프(Heap Dump) 분석기(MAT 등)**를 켜서 지난밤의 메모리 파형 그래프를 분석한다. 계단식으로 RAM 사용량이 올라가다 터진 궤적을 확인하고, 어떤 객체가 메모리를 점유하고 있는지 소스 코드 단위로 추적(Profiling)한다. 보통 쓰레드 로컬(ThreadLocal)의 미해제나 무한 루프가 원인이다. 코드의 메모리 할당 릭(Leak)을 고친 후 다시 72시간 런닝(Soak Test)을 돌려 메모리 그래프가 수평을 그리는지 확인해야 완벽한 준공 승인이 떨어진다.
도입 체크리스트
- 더미 데이터(Dummy Data)의 다양성: 테스트를 돌릴 때 회원 ID
user01딱 하나만 넣고 결제 로직 1만 번을 때려 넣고 있는가? (최악의 초보 실수다). 오라클 DB는 처음 날아온user01쿼리의 결과를 똑똑하게 메모리(Buffer Cache)에 저장해 둔다. 두 번째부터는 디스크(하드)를 안 읽고 메모리에서 1초 만에 답을 줘버린다. 결과적으로 DB 성능이 100배 부풀려진 사기(Cache Hit) 테스트가 돼버린다. 부하 테스트를 할 때는 반드시 엑셀 파일(CSV)로user01부터user10000까지 1만 개의 서로 다른 아이디와 파라미터를 파이프라인에 물려서, DB가 교묘하게 캐싱(Caching) 꼼수를 쓰지 못하도록 실전과 똑같이 가혹하게 괴롭혀야 한다.
Ⅳ. 기대효과 및 결론
정량/정성 기대효과
| 구분 | 기능 테스트만 완료 후 배포 (Big Bang) | 4대 성능 테스트(Load/Stress 등) 완료 후 배포 | 비즈니스 생존율 및 ROI |
|---|---|---|---|
| 정량 (장애 대응 비용) | 오픈 직후 트래픽 몰리며 서버 다운, 매출 손실 | 스파이크 대비 오토스케일링 셋팅으로 방어 | 대형 이벤트(명절/블프) 시 기회비용 손실 제로(0)화 |
| 정량 (인프라 자원 최적화) | 막연한 불안감에 비싼 서버 10대 무지성 증설 | 임계점 파악을 통해 딱 필요한 서버 3대만 증설 | 오버프로비저닝 방지로 클라우드 비용 70% 삭감 |
| 정성 (아키텍처 가시성) | "서버가 왜 죽었는지 모르겠어. 재부팅 해" | "DB 커넥션 부족이 병목(Bottleneck)입니다" | 감(Guess)이 아닌 수치(TPS, Latency) 기반의 과학적 튜닝 문화 정착 |
"모든 시스템은 결국 부러진다. 성능 테스트의 목적은 시스템이 부러지지 않게 하는 것이 아니라, 시스템이 어디서 어떻게 부러지는지를 알고, 부러졌을 때 우아하게(Graceful Degradation) 무너지는 법을 가르치는 것이다." 성능 테스트는 코드 단위의 좁은 시야를 넘어, 브라우저 ─▶ L4 로드밸런서 ─▶ 웹서버 ─▶ DB에 이르는 거대한 고속도로를 위에서 굽어보는 아키텍트 전용 망원경이다. 기술사는 아무리 화려하고 우아한 클린 코드(Clean Code)를 짰다 하더라도, 1만 명의 트래픽 압력기(Stress) 앞에서는 한낱 지푸라기처럼 타버릴 수 있음을 겸손하게 인정하고, 출시 전 반드시 시스템을 가혹한 지하실(JMeter)에 가둬 극한의 인듀어런스(마라톤) 훈련을 통과한 무쇠의 성벽으로 벼려내야 한다.
📌 관련 개념 맵 (Knowledge Graph)
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| TPS (Throughput) | 초당 처리 건수. 성능 테스터들의 최종 성적표이자 심장 박동수. "우리 은행 시스템은 10,000 TPS까지 버틴다!"라고 당당하게 말할 수 있어야 진짜 전문가다. |
| APM (Application Performance Mgmt) | JMeter가 밖에서 총을 쏘는 적군이라면, 제니퍼(Jennifer)나 와탭(Scouter) 같은 APM은 서버 안에서 "총알이 DB 락에 걸렸어!"라고 엑스레이를 찍어주는 아군의 최강 투시경이다. |
| 스케일 아웃 (Scale-out) | 성능 테스트 결과 TPS 한계점이 너무 낮게 나오면, CPU를 비싼 걸로 바꾸는 대신 싼 서버 10대로 수평으로 쫙 찢어서 짐을 나누는(Load Balancing) 해결책. |
| 가비지 컬렉터 (GC, Garbage Collector) | 자바(Java) 언어의 청소부. 인듀어런스(Soak) 테스트를 돌리면 이 청소부가 쓰레기(메모리)를 제대로 못 치워서 메모리가 폭발(OOM)하는 장면을 가장 많이 목격하게 된다. |
| 카오스 엔지니어링 (Chaos Engineering) | 성능 테스트의 미친 진화형. 넷플릭스가 만든 기법으로, 가상 트래픽을 주는 걸 넘어 아예 라이브 운영 서버의 랜선을 무작위로 뽑아버리면서(Chaos) 시스템이 견디는지 보는 미친 훈련법. |
👶 어린이를 위한 3줄 비유 설명
- 내가 만든 레고 다리가 얼마나 튼튼한지 친구들에게 자랑하려고 해요. 기능 검사는 그냥 자동차 한 대 굴려보며 "잘 굴러가네!" 하는 거예요.
- 하지만 진짜 성능 검사는 달라요! 모래주머니 10kg(부하)을 올려보고, 100kg(스트레스)을 올려서 다리가 쩌억 갈라지는 약점을 찾아내죠!
- 심지어 위에서 갑자기 수박을 확 떨어뜨려 보고(스파이크), 1주일 내내 무거운 돌을 올려두고 놔둬보면서(인듀어런스) 절대로 안 무너지는 완벽한 튼튼함을 과학적으로 증명하는 엄청난 파괴 시험이랍니다!