성능 테스트
고친 사람 github-actions[bot]
성능 테스트는 시스템이 일을 얼마나 빨리, 얼마나 많이 해내는지 재는 시험입니다. 답이 맞는지를 보는 시험과 달리 속도와 양을 숫자로 봅니다. 사용자가 몰려 느려지는 일을 운영에 올리기 전에 미리 찾아내려는 것입니다.
쉽고 빠른 이해
무슨 일을 하는 시험인가 — 요청을 보내 놓고 답이 몇 초 만에 오는지, 1초에 몇 건을 끝내는지, 기계를 얼마나 쓰는지 잽니다. 「요청 100건 중 95건이 0.2초 안에 끝나야 한다」 같은 기준을 세워 두고 견줍니다.
왜 하나 — 한 사람이 한 번 눌러 보는 시험에서는 느려짐이 잘 드러나지 않습니다. 여럿이 몰려 자원 하나가 꽉 차면 응답이 받아들일 수 없을 만큼 느려집니다. 그런 느려짐은 설계에서 비롯될 때가 많습니다. 늦게 찾을수록 고칠 범위가 넓어집니다.
어떻게 도나
- 합격 기준을 숫자로 정합니다
- 운영과 닮은 환경에서 여러 사용자를 흉내 낸 요청을 겁니다
- 값이 안정된 구간의 숫자를 모아 기준과 견줍니다
대가 — 시험 환경을 운영 환경에 맞추는 데 돈과 사람이 듭니다. 덜 맞출수록 나온 숫자를 운영에 옮겨 읽기 어려워집니다.
상세
식당이 문을 열기 전에 지인 쉰 명을 한꺼번에 불러 시범 영업을 합니다. 이날 보는 것은 음식 맛이 아닙니다. 주문이 몰릴 때 한 상이 몇 분 만에 나오는지, 한 시간에 몇 상을 내는지를 봅니다.
성능 테스트는 컴포넌트나 시스템의 성능 효율성을 판정하는 시험입니다. 성능 효율성은 정해 둔 조건에서 시간과 처리량 기준을 맞추면서 자원을 얼마나 알뜰하게 쓰는지를 가리킵니다. 「요청의 95%가 200ms(밀리초) 안에 끝나야 한다」가 그런 기준 하나입니다.
여기서 말하는 조건은 거는 부하의 크기, 쌓아 둔 데이터의 양, 시험하는 환경 같은 것입니다. 부하는 시스템에 한꺼번에 걸리는 일감의 양입니다. 같은 시스템이어도 조건이 바뀌면 숫자가 바뀝니다. 그래서 숫자는 늘 조건과 함께 적습니다.
성능 효율성을 이루는 세 특성
성능 효율성은 비기능 품질 특성의 하나입니다. 비기능 품질 특성은 기능이 맞게 도는지가 아니라 얼마나 잘 도는지를 가리키는 속성입니다. 성능 효율성은 아래 세 하위 특성으로 나눠 봅니다.
| 특성 | 묻는 것 | 재는 것의 예 |
|---|---|---|
| 시간 동작 | 정해 둔 시간 안에 입력에 답하나 | 사용자 입력에서 응답까지 걸린 시간 · 한 구성 요소가 일을 끝내는 데 쓴 CPU(Central Processing Unit, 중앙처리장치) 사이클 수 |
| 자원 사용 | 자원을 얼마나 쓰나 | 한정된 RAM(Random Access Memory, 주 메모리)을 얼마나 차지하나 |
| 용량 | 요구하는 상한에서 버티나 | 사용자 수 · 데이터 양의 상한 |
CPU 는 계산을 하는 칩입니다. RAM 은 프로그램이 돌면서 값을 올려 두는 메모리입니다.
셋 가운데 대개 가장 흔한 목표는 시간 동작입니다. 자원이 모자랄 위험이 있다고 보면 자원 사용을 따로 재는 시험을 합니다. 상한에서 어떻게 도는지가 위험으로 꼽히면 용량을 따로 재는 시험을 합니다.
함께 보는 네 값
결과는 대개 아래 네 값으로 읽습니다. 하나만 읽으면 그 값이 멀쩡한 동안 나머지가 무너진 것을 놓칩니다.
| 재는 것 | 뜻 | 이것만 보면 놓치는 것 |
|---|---|---|
| 응답 시간 | 요청을 보내고 답을 받기까지 걸린 시간 | 같은 시간에 몇 건을 끝냈는지 |
| 처리량 | 정해진 시간 동안 끝낸 요청 수. 흔히 초당 요청 수로 적는다 | 한 사람이 얼마나 기다렸는지 |
| 오류율 | 받은 요청 중 실패로 끝난 비율 | 성공한 요청이 얼마나 느렸는지 |
| 자원 사용률 | CPU · 메모리 · 디스크 · 네트워크가 얼마나 찼는지 | 사용자가 겪는 속도 |
처리량과 응답 시간은 따로 놀지 않습니다. 초당 요청 수가 늘면 응답 시간도 늘어나는 일이 흔합니다. 어느 부하를 넘어서면 응답 시간이 낭떠러지처럼 치솟는 서비스도 흔합니다. 아래 그림은 그 모양만 보이려고 고른 값입니다.
xychart-beta
title "초당 요청 수에 따른 응답 시간"
x-axis ["100", "200", "300", "400", "500", "600"]
y-axis "응답 시간(ms)" 0 --> 2000
line [50, 55, 65, 90, 400, 1800]
그림에서 볼 것은 꺾이는 지점입니다. 그 앞에서는 요청을 더 넣어도 응답 시간이 조금씩만 늘어납니다. 그 뒤로는 조금만 더 넣어도 크게 늘어납니다.
기능 시험과 다른 점
기능 시험은 입력 하나를 넣어 답이 맞는지 가립니다. 성능 테스트에 넣는 입력은 부하입니다. 부하도 시험 입력이라는 점은 같습니다. 다른 점은 아래 셋입니다.
| 기능 시험의 입력 | 성능 테스트의 부하 | |
|---|---|---|
| 몇 사람 몫인가 | 한 사용자의 입력 하나 | 많은 사용자의 입력 |
| 만드는 데 드는 것 | 시험 코드 | 전용 하드웨어와 도구가 필요할 수 있음 |
| 무엇이 먼저 돼야 하나 | 없음 | 시험을 막는 기능 결함이 없어야 함 |
많은 사용자의 입력은 도구가 흉내 냅니다. 도구가 흉내 내는 사용자 하나를 가상 사용자라고 부릅니다. 가상 사용자는 미리 짜 둔 순서대로 요청을 보내고 답을 받습니다.
답의 꼴도 다릅니다. 기능 시험의 답은 맞음과 틀림 둘 중 하나입니다. 성능 테스트의 답은 숫자입니다. 숫자 자체에는 통과도 실패도 없어서 시험 전에 합격 기준을 정해 두어야 판정이 됩니다.
부하를 건 채로 기능이나 사용성 같은 다른 품질 특성을 함께 보기도 합니다. 그러면 부하가 걸릴 때만 생기는 문제가 드러날 수 있습니다.
성능 테스트는 웹 서비스에만 쓰지 않습니다. 클라이언트-서버 · 분산 시스템 · 임베디드 시스템에도 씁니다.
믿을 만한 결과의 조건
성능 테스트 결과가 쓸모 있으려면 아래를 지켜야 합니다.
| 조건 | 뜻 |
|---|---|
| 기대에 맞춘다 | 사용자 · 시스템 설계자 · 운영 담당자가 기대하는 바에 맞춰 시험을 짠다 |
| 재현된다 | 바뀌지 않은 시스템에서 되풀이하면 미리 정한 허용 오차 안에서 통계적으로 같은 결과가 나와야 한다 |
| 견줄 수 있다 | 결과가 이해하기 쉽고 이해관계자의 기대와 바로 견줄 수 있어야 한다 |
| 운영을 대표한다 | 자원이 허락하면 전체 시스템에서 한다. 시스템의 일부에서 하거나, 운영 시스템을 닮게 꾸린 시험 환경에서 해도 된다 |
| 감당할 수 있다 | 프로젝트가 정한 기간과 비용 안에서 돌릴 수 있어야 한다 |
배경
기능 시험은 사용자 한 명이 한 번 누르는 경우를 봅니다. 성능 결함은 이 꼴에서 잘 안 드러납니다. 예상 범위 안의 부하에서도 자원 하나 이상이 포화되면 응답이 받아들일 수 없을 만큼 느려지는 일이 있습니다.
오래 돌면서 응답이 점점 나빠지기도 합니다. 메모리 누수 · 디스크 단편화 · 예상 밖으로 커진 데이터베이스가 그 원인으로 꼽힙니다.
이런 결함 중 치명적인 것 상당수는 아키텍처와 설계 단계에서 들어옵니다. 운영에 올린 뒤 사용자가 먼저 겪으면 고칠 범위가 설계까지 번집니다. 그래서 많은 사용자의 입력을 흉내 낸 부하를 일부러 만들어 미리 재는 시험이 따로 섭니다. 부하의 양을 바꿔 가며 응답성을 보는 시험을 통틀어 성능 테스트라고 부릅니다.
같은 까닭으로 코드를 돌리기 전에 설계를 검토하는 정적 테스트가 기능 시험보다 성능 쪽에서 더 중요한 경우가 많습니다.
일찍 시작하면 아키텍처의 병목을 고치기 비싸지기 전에 잡습니다. 대가는 전용 인프라와 전문 인력에 드는 운영 비용입니다. 이 비용을 늦게 찾은 성능 문제나 운영 장애의 비용과 견줘 어디까지 할지 정합니다.
예시
성능 테스트는 무엇의 시간을 재느냐에 따라 모습이 다릅니다. 아래 셋은 웹 서버 · 데이터베이스 · 브라우저 화면을 재는 도구입니다. 저마다 내놓는 값이 다릅니다.
ab
ab 는 Apache HTTP(HyperText Transfer Protocol) 서버를 벤치마크하는 도구입니다. 지금 설치한 Apache 가 1초에 요청을 몇 개나 처리할 수 있는지 보여 줍니다. 여기서 볼 옵션은 둘입니다.
| 옵션 | 뜻 | 기본값 |
|---|---|---|
-n requests |
이번에 보낼 요청 수 | 요청 하나. 대개 대표성 없는 결과로 이어진다 |
-c concurrency |
한 번에 동시에 보내는 요청 수 | 한 번에 하나 |
결과에는 아래 줄이 찍힙니다.
| 출력 줄 | 뜻 |
|---|---|
Concurrency Level |
시험에 쓴 동시 클라이언트 수 |
Time taken for tests |
첫 소켓 연결을 맺은 때부터 마지막 응답을 받은 때까지 |
Complete requests |
성공한 응답 수 |
Failed requests |
실패로 친 요청 수 |
Requests per second |
요청 수를 걸린 시간 전체로 나눈 값 |
Time per request |
요청 하나에 든 평균 시간. 두 값이 찍힌다 |
Time per request 의 첫 값은 concurrency * timetaken * 1000 / done 입니다. 둘째 값은 timetaken * 1000 / done 입니다. 첫 값은 둘째 값에 동시 요청 수를 곱한 것이어서, 동시 요청 수가 1보다 크면 둘째 값이 더 작게 나옵니다.
앞의 네 값으로 옮기면 Requests per second 가 처리량, Failed requests 가 오류입니다. 응답 시간에 해당하는 것은 Time per request 의 첫 값입니다.
pgbench
pgbench 는 PostgreSQL 에 벤치마크를 돌리는 도구입니다. 같은 SQL(Structured Query Language) 명령 묶음을 되풀이해 실행합니다. 여러 데이터베이스 세션에서 동시에 돌릴 수도 있습니다. 끝나면 평균 처리량을 tps(transactions per second, 초당 트랜잭션 수)로 냅니다.
-c clients 는 흉내 낼 클라이언트 수, 곧 동시에 여는 데이터베이스 세션 수입니다. 기본값은 1입니다. -T seconds 는 클라이언트당 트랜잭션 수를 정하는 대신 정한 초만큼 돌립니다. 흔한 출력은 이렇게 생겼습니다.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 10
number of threads: 1
maximum number of tries: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
number of failed transactions: 0 (0.000%)
latency average = 11.013 ms
latency stddev = 7.351 ms
initial connection time = 45.758 ms
tps = 896.967014 (without initial connection time)
클라이언트 10개가 저마다 트랜잭션 1000개를 돌려 10000개를 모두 처리했습니다. 실패한 트랜잭션은 0개입니다.
앞의 네 값으로 옮기면 latency average 가 응답 시간, tps 가 처리량, number of failed transactions 가 오류입니다.
한 트랜잭션의 응답 시간 평균은 11.013ms 입니다. 표준편차는 7.351ms 입니다. 처리량은 초당 약 897건입니다. 이 값은 처음 연결을 맺는 데 든 시간을 뺀 것입니다.
Lighthouse
Lighthouse 는 웹 페이지의 품질을 높이는 데 쓰는 오픈 소스 자동화 도구입니다. 성능 · 접근성 · 검색 엔진 최적화 같은 항목을 점검합니다. Chrome 개발자 도구나 명령줄에서 돌립니다. URL(Uniform Resource Locator) 하나를 주면 그 페이지에 점검을 차례로 돌려 보고서를 냅니다.
앞의 두 도구는 동시 요청 수(-c)를 옵션으로 정합니다. Lighthouse 는 페이지 하나를 받아 그 페이지의 지표를 잽니다. 성능 점수는 지표 점수의 가중 평균입니다. Lighthouse 10 의 가중치는 아래와 같습니다.
| 지표 | 가중치 |
|---|---|
| First Contentful Paint | 10% |
| Speed Index | 10% |
| Largest Contentful Paint | 25% |
| Total Blocking Time | 30% |
| Cumulative Layout Shift | 25% |
다섯 가운데 여기서 뜻을 푸는 것은 LCP(Largest Contentful Paint) 하나입니다.
LCP 는 페이지에서 가장 큰 콘텐츠가 보인다고 사용자가 느끼는 때를 잽니다. 값은 사용자가 페이지를 불러오기 시작한 때부터 주된 콘텐츠가 그려지기까지의 시간입니다.
지표 점수는 실제 웹사이트에서 모은 값에 맞춰 매깁니다. 상위 사이트가 LCP 를 약 1,220ms 에 그리기 때문에 그 값이 99점이 됩니다. 점수는 세 구간으로 읽습니다. 0~49 가 Poor, 50~89 가 Needs Improvement, 90~100 이 Good 입니다.
점수는 흔들립니다. 그 원인은 대개 Lighthouse 가 아니라 바탕 조건입니다. A/B 테스트(두 판을 나눠 보여 주고 견주는 실험)나 광고 변경 · 인터넷 경로 변경 · 다른 기기에서 잰 것 · 브라우저 확장 프로그램 · 백신 프로그램이 꼽힙니다. 그래서 페이지 성능을 숫자 하나보다 점수의 분포로 보는 편이 더 쓸모 있을 수 있습니다.
갈래
성능 테스트는 여러 시험을 아우르는 이름입니다. 무엇을 알아내려 하느냐가 축입니다. 그 목적에 따라 부하의 크기와 모양, 거는 시간이 정해집니다.
부하 테스트
예상하는 현실적인 부하를 단계적으로 올려 가며 시스템이 받아내는지 봅니다. 부하는 미리 정한 수의 동시 사용자나 프로세스가 보내는 트랜잭션 요청으로 만듭니다. 일찍 시작해 자주 돌리는 시험입니다. 기준 성능 · 용량 한계 · 확장이 잘 먹히는지를 드러냅니다.
스트레스 테스트
예상하거나 명시한 작업량의 한계에 닿거나 그것을 넘는 최대 부하를 겁니다. 계산 능력 · 대역폭 · 메모리 같은 자원을 줄여 놓고 버티는지 볼 때도 씁니다. 최대 용량과 무너지는 모습, 무너진 뒤 회복하는 모습을 드러냅니다.
확장성 테스트
지금 요구보다 큰 앞으로의 요구를 맞출 수 있는지 봅니다. 사용자를 늘리거나 저장 데이터를 키워 가며, 지금 정한 성능 요구를 어기거나 멈추지 않고 자랄 수 있는지 가립니다.
스파이크 테스트
최대 부하가 갑자기 몰렸을 때 제대로 응답하는지 봅니다. 몰린 뒤 안정된 상태로 돌아오는지도 봅니다. 자동 확장이 얼마나 빨리 반응하는지, 큐가 몰린 요청을 어떻게 다루는지, 기능을 줄여서라도 버티는지를 드러냅니다.
내구 테스트
시스템이 놓인 운영 맥락에 맞는 긴 시간 동안 안정한지 봅니다. 소크 테스트라고도 부릅니다. 메모리 누수 · 데이터베이스 연결 · 스레드 풀처럼 끝내 성능을 떨어뜨리거나 고장을 낼 수 있는 자원 문제가 없는지 확인합니다.
동시성 테스트
특정 동작이 한꺼번에 일어날 때의 영향을 봅니다. 많은 사용자가 같은 때에 로그인하는 경우가 그 예입니다.
용량 테스트
정한 성능 목표를 지키면서 사용자나 트랜잭션을 몇까지 받는지 정합니다. 목표는 트랜잭션이 쌓는 데이터 양으로 적기도 합니다.
종류마다 드러내는 것이 달라서 여러 종류를 함께 씁니다. 스트레스 테스트는 최대 부하에서 깨지는 지점을 찾습니다. 몇 시간이나 며칠에 걸쳐 드러나는 메모리 누수는 내구 테스트만 드러냅니다.
운영
성능 테스트는 끝까지 돌고도 뜻 없는 숫자를 내기 쉽습니다. 아래 다섯 소절은 숫자가 틀어지는 원인과 볼 지표입니다. 마지막 소절은 판정에 쓰는 기준입니다.
시험 환경과 운영 환경의 차이
시험 환경은 운영 환경에 되도록 가까워야 합니다. 성능은 환경의 비선형 함수입니다. 환경을 운영보다 조금 줄였다고 성능도 그만큼만 줄어드는 것이 아니라는 뜻입니다.
환경이 운영과 멀어질수록 운영에서의 성능을 내다보기 어려워집니다. 그만큼 위험도 커집니다.
가장 중요한 요소는 데이터 · 하드웨어와 소프트웨어 설정 · 네트워크 설정입니다. 데이터의 크기와 구조는 결과를 크게 바꿀 수 있습니다. 운영이 큰 데이터를 쓸 때 작은 표본으로 재면 그릇된 결과가 나올 수 있습니다.
가상 사용자 여럿이 같은 사용자 이름으로 같은 데이터에 접근해도 결과가 틀어집니다. 데이터가 디스크에서 메모리로 전부 캐시되면 결과가 운영보다 훨씬 좋게 나옵니다. 반대로 한 사용자가 고치는 데이터에 락이 걸리면 다음 사용자가 기다려서 운영보다 훨씬 나쁘게 나옵니다.
어디까지 맞출지는 위험에 따라 정합니다. 핵심 업무 시스템이면 계산 자원 사양 · 자동 확장 설정 · 캐시 설정 · 네트워크 조건 · 외부 의존성까지 운영과 똑같이 맞춥니다. 핵심이 아니면 운영을 흉내 낸 축소 환경에서도 적은 비용으로 쓸 만한 통찰을 얻을 수 있습니다.
정상 상태와 램프업
성능 테스트는 대개 시스템의 정상 상태를 잽니다. 정상 상태는 흉내 낸 사용자가 모두 들어와 짜 둔 대로 일하고 있어서 거동이 안정된 때입니다. 부하가 바뀌는 동안에는 거동도 바뀌어서 결과를 보고 분석하기가 어렵습니다.
정상 상태에 이르는 단계를 흔히 램프업이라 부릅니다. 시험을 끝내는 단계는 램프다운이라 부릅니다. 한 회차는 아래 모양으로 흐릅니다. 그림의 값은 모양만 보이려고 고른 것입니다.
xychart-beta
title "한 회차 동안의 가상 사용자 수"
x-axis ["0분", "1분", "2분", "3분", "4분", "5분"]
y-axis "가상 사용자 수" 0 --> 120
line [0, 50, 100, 100, 100, 0]
숫자를 모으는 구간은 평탄한 가운데입니다. 올라가고 내려가는 양 끝은 거동이 바뀌는 구간입니다. 스파이크 테스트나 한꺼번에 몰리는 로그인처럼 바뀌는 구간 자체를 재야 할 때도 있습니다. 그때는 평균을 보는 흔한 방법이 크게 오도할 수 있습니다.
몇 초만 돌린 결과는 믿지 않습니다. 잡음을 평균내려면 적어도 몇 분은 돌립니다. 되풀이할 수 있는 숫자를 얻는 데 몇 시간이 필요한 경우도 있습니다. 몇 번 돌려 보아 숫자가 되풀이되는지 확인합니다.
데이터가 시간에 따라 바뀌는 것도 봐야 합니다. pgbench 기본 시나리오는 테이블을 초기화한 뒤 얼마나 지났는지에 민감합니다. 죽은 행과 빈 공간이 쌓이면서 결과가 바뀝니다. 죽은 행은 지워지거나 갱신돼 더는 보이지 않는데도 아직 파일에 남아 있는 행입니다.
부하 생성기의 병목
부하 생성기는 부하를 만들어 보내는 쪽 기계와 도구입니다. 이쪽이 먼저 막히면 시험 대상이 아니라 부하 생성기를 재게 됩니다.
ab 는 자기 코드에서 strstr(3) 를 많이 씁니다. strstr(3) 는 문자열 안에서 다른 문자열을 찾는 C 표준 라이브러리 함수입니다. ab 자신을 프로파일링하면 이 호출이 시간을 많이 쓴 함수 상위에 뜹니다.
이것은 ab 쪽에 성능 문제가 있다는 뜻일 수 있습니다. 그러면 서버가 아니라 ab 의 성능을 재게 됩니다.
pgbench 도 클라이언트 세션을 많이 흉내 낼 때 스스로 병목이 될 수 있습니다. 데이터베이스 서버와 다른 기계에서 돌리면 이 문제를 덜 수 있습니다. 이때 두 기계 사이 네트워크 지연이 낮아야 합니다. 여러 클라이언트 기계에서 pgbench 를 동시에 돌리는 것도 방법이 될 수 있습니다.
그래서 시험하는 동안 부하 생성기 자체에도 모니터를 붙이기도 합니다. 요청을 여러 곳에서 보내면 현실감이 생깁니다. 다만 중간 네트워크 구간이 지연을 만들어 결과를 비틀 수도 있습니다.
평균과 백분위수
백분위수는 값을 작은 것부터 줄 세웠을 때 어느 순번에 있는 값입니다. 요청 100개의 응답 시간을 줄 세워 99번째 값을 읽으면 99번째 백분위수입니다. 흔히 p99 로 적습니다. 50번째 백분위수는 중앙값입니다.
응답 시간을 평균 하나로 줄이면 꼬리가 가려집니다. 대부분의 요청이 금방 끝나도 일부 요청은 훨씬 오래 걸릴 수 있기 때문입니다. 어떤 서비스는 전형적인 요청이 약 50ms 에 끝납니다. 그런데 요청의 5%는 그 20배가 걸립니다.
50번째 백분위수는 전형적인 경우를 보여 줍니다. 99번째나 99.9번째 같은 높은 백분위수는 가장 오래 기다리는 쪽에서 있을 법한 값을 보여 줍니다. 응답 시간의 편차가 클수록 사용자 경험이 꼬리에 끌려갑니다. 높은 부하에서는 요청이 줄을 서서 기다리는 탓에 이 효과가 더 커집니다.
평균은 이상치에 쉽게 끌려갑니다. 그래서 90번째 백분위수를 목표로 자주 씁니다. 사용자 대다수가 그 기준에 닿는다는 뜻이기 때문입니다.
처리량도 평균에 가려집니다. 짝수 초마다 200건을 처리하고 홀수 초에는 0건을 처리하는 시스템이 있다고 합시다. 평균은 꾸준히 100건씩 처리하는 시스템과 같습니다. 순간 부하는 평균의 두 배입니다.
xychart-beta
title "평균이 같은 두 시스템의 초당 처리 건수"
x-axis ["1초", "2초", "3초", "4초", "5초", "6초"]
y-axis "처리 건수" 0 --> 220
bar [0, 200, 0, 200, 0, 200]
line [100, 100, 100, 100, 100, 100]
막대는 짝수 초에만 200건을 처리하는 시스템입니다. 선은 꾸준히 100건씩 처리하는 시스템입니다. 1분 동안 모아 평균을 내면 두 시스템이 같아 보입니다. 1초 단위로 보면 막대 쪽은 짝수 초에 평균의 두 배를 받아 냅니다.
닫힌 모델과 열린 모델
가상 사용자를 어떻게 굴리느냐에 따라 숫자가 틀어지기도 합니다. 닫힌 모델에서는 가상 사용자가 앞 반복을 끝내야 다음 반복을 시작합니다. 열린 모델에서는 반복이 끝나든 말든 새 반복이 들어옵니다. 새 반복이 1초에 몇 개 시작되는지를 도착률이라고 부릅니다.
sequenceDiagram
participant 가상 사용자
participant 서버
가상 사용자->>서버: 요청 1
Note over 서버: 부하로 응답이 느려진다
서버-->>가상 사용자: 늦은 응답 1
Note over 가상 사용자: 응답을 받은 뒤에야 다음 반복을 시작한다
가상 사용자->>서버: 요청 2
닫힌 모델에서는 대상 시스템의 응답 시간이 시험의 처리량에 끼어들 수 있습니다. 응답이 느려지면 반복이 길어집니다. 그만큼 새 반복이 늦게 도착합니다.
시스템이 버거워 느려지기 시작하면 닫힌 모델 시험은 그만큼 기다립니다. 그래서 걸려고 한 부하보다 적게 걸립니다. 몇몇 테스트 문헌은 이 문제를 coordinated omission 이라고 부릅니다. 정한 도착률이나 초당 요청 수를 흉내 내려는 시험에는 맞지 않습니다.
열린 모델은 반복을 반복 시간과 떼어 놓습니다. 대상 시스템의 응답 시간이 더는 부하에 끼어들지 않습니다.
sequenceDiagram
participant 부하 도구
participant 서버
부하 도구->>서버: 요청 1
Note over 부하 도구: 응답을 안 기다리고 정한 간격대로 보낸다
부하 도구->>서버: 요청 2
부하 도구->>서버: 요청 3
서버-->>부하 도구: 늦은 응답 1
부하 도구 k6 에는 아래 네 실행기가 있습니다. 앞의 둘은 닫힌 모델입니다. 뒤의 둘은 열린 모델입니다. 이름의 vus 는 가상 사용자(virtual users)를 줄인 것입니다.
| 실행기 | 모델 | 하는 일 |
|---|---|---|
constant-vus |
닫힌 모델 | 정한 수의 가상 사용자가 정한 시간 동안 반복을 할 수 있는 만큼 돌린다 |
ramping-vus |
닫힌 모델 | 가상 사용자 수를 바꿔 가며 정한 시간 동안 반복을 할 수 있는 만큼 돌린다 |
constant-arrival-rate |
열린 모델 | 정한 기간에 정한 수의 반복을 실행한다 |
ramping-arrival-rate |
열린 모델 | 정한 기간에 실행할 반복 수를 바꿔 간다 |
합격 기준과 기준선
판정은 지표마다 정한 임계값으로 합니다. 그래야 시험이 통과와 실패를 또렷하게 냅니다. SLO(Service Level Objective, 서비스 수준 목표)가 「요청의 95%가 200ms 안에 끝난다」면 응답 시간 임계값을 95번째 백분위수 200ms 로 둡니다. 95번째 백분위수가 200ms 를 넘은 회차는 실패입니다.
k6 에서는 이 합격 기준을 thresholds 로 적습니다. 대상 시스템이 임계값 조건을 못 맞추면 시험이 실패 상태로 끝납니다. 시험하는 사람은 흔히 SLO 를 이 값으로 옮겨 적습니다. 「요청의 1% 미만이 오류를 낸다」 · 「요청의 95%가 200ms 안에 응답한다」 · 「요청의 99%가 400ms 안에 응답한다」 같은 조건을 엮어 씁니다.
기준선은 시험으로 확인한 정상 조건의 지표 묶음입니다. 처음 회차의 지표를 기록해 기준선으로 삼습니다. 다음 회차부터는 새 결과를 기준선과 견줘 성능이 바뀌었는지 찾습니다. 코드 · 설정 · 인프라가 바뀌어 기준선보다 성능이 떨어진 것을 성능 회귀라고 부릅니다.
관련 항목
성능 테스트가 재는 지표
응답 시간 · 처리량 · 오류율 · 초당 요청 수 · 초당 트랜잭션 수 · 백분위수 · 평균 · 자원 사용률 · 포화도 · 꼬리 지연 · LCP
성능 테스트의 하위 종류
부하 테스트 · 스트레스 테스트 · 확장성 테스트 · 스파이크 테스트 · 내구 테스트 · 소크 테스트 · 동시성 테스트 · 용량 테스트 · 스모크 테스트
성능 테스트와 견주는 다른 시험
기능 테스트 · 정적 테스트 · 벤치마크 · 회귀 테스트 · 시스템 테스트
성능 테스트에 쓰는 도구
Locust · k6 · Gatling · JMeter · pgbench · wrk · ab · Lighthouse
부하를 거는 방식을 이루는 개념
부하 · 가상 사용자 · 램프업 · 정상 상태 · 동시성 · 생각 시간 · 테스트 시나리오 · 워크로드 · 열린 모델 · 닫힌 모델 · coordinated omission
성능 테스트가 찾아내는 병목
병목 · 커넥션 풀 · 스레드 풀 · 락 경합 · 가비지 컬렉션 · 메모리 누수 · N+1 · 큐잉 이론
성능 테스트가 사용률을 재는 자원
자원 · CPU · 메모리 · 디스크 · 네트워크 · 데이터베이스
성능 테스트 결과로 정하는 약속
서비스 수준 목표 · 서비스 수준 지표 · 서비스 수준 계약 · 기준선 · 용량 계획 · 자동 확장 · 타임아웃
성능 테스트 뒤에 원인을 파는 수단
프로파일링 · 모니터링 · 분산 추적 · 플레임 그래프 · 성능 분석 · 인덱스 · 캐싱
성능 테스트가 속하는 상위 분류
다른 이름: performance testing · performance test · 퍼포먼스 테스트 · 성능 시험