Projects/hub-eleven

[부하테스트] 재고 API - (1) k6로 테스트 해보기

annovation 2026. 7. 24. 23:59

1. 가설 : 문제점 제기

 

가설 1

 

가설 2

 

2. 어떻게 테스트 해볼 수 있을까? -> 부하테스트 -> k6 테스트 : 왜 k6 ?

 


코드 구현

k6는 크게 두 가지 방식으로 부하를 만들 수 있다.

 

💡Closed Model (vus / ramping-vus executor)

  • 이전 Iteration이 끝나야 다음 Iteration이 시작되는 모델
    (Iteration : Virtual User(VU)가 default() 함수를 한 번 처음부터 끝까지 실행하는 것을 의미)
"The next iteration doesn't start until the previous one finishes."
  • 흐름 예시
VU 1 -> HTTP 요청 -> 응답 대기 -> 응답 완료 -> 다음 요청 시작
  • 새로운 요청 시작 시점이 이전 요청이 언제 끝났는지에 의존한다.
  • 코드 예시
예시

 

❗️문제점

  • 부하가 없는 정상적인 서버의 응답시간이 100ms 라고 가정했을 때, 1초동안 약 10번의 요청을 보낼 수 있다.
  • 그런데 부하로 인해 서버가 느려지고 응답시간이 2초가 되었지만, closed model 은 응답을 받아야 VU가 다음 요청을 보낼 수 있기 때문에 오히려 부하가 줄어드는 현상이 생긴다.
  • 이 현상을 Coordinated Omission 이라고 한다.
"Slower response times means longer iterations and a lower arrival rate."
응답이 느려질수록 요청 도착률(Arrival Rate)도 함께 줄어드는 문제
  • 흐름 예시
응답시간

100ms

↓

1초에

10번 요청

----------------

응답시간

2초

↓

2초에

1번 요청

 

💡Open Model (constant-arrival-rate / ramping-arrival-rate executor)

  • Closed Model의 문제를 해결하기 위해 나온 모델
  • 핵심은, 응답이 끝났는지와 관계없이 새로운 요청을 시작한다는 것
"VU iterations arrive independently of iteration completion."
  • 흐름 예시
1초 -> 무조건 요청 시작 -> 응답 기다리지 않음 -> 2초 -> 또 요청 시작
  • 코드 예시
예시

 

❗️왜 Open Model이 필요할까?

  • 실제 서비스는 사용자가 응답이 느리다고 새로운 사용자가 안 들어오는 것은 아니다.
  • 예를 들어, 네이버에서 
  • 따라서, Open Model 이 현실 트래픽을 더 잘 모방한다고 할 수 있다.

💡비교

항목 Closed Model Open Model
요청 시작 기준 이전 Iteration 종료 후 시작 정해진 시간마다 시작
응답시간 영향 받음 받지 않음
부하량 응답이 느려질수록 감소 일정하게 유지
현실 트래픽 재현 상대적으로 낮음 높음
대표 Executor constant-vus, ramping-vus constant-arrival-rate, ramping-arrival-rate
  • Open : 이 API의 최대 지속 가능 처리량(천장)은 어디인지 = 한계점 찾기(capacity test)
  • Closed : 한계 안에서 동시성이 오를 때 어떻게 저하되고, 리팩토링으로 얼마나 개선됐는지 = 저하 특성 + 전후 비교

프로젝트에 적용된 파일 구조

product/load-test/
├── README.md                      # 실행 방법, 사전 준비(시딩), 결과 해석
├── seed/
│   └── seed.sql                   # 테스트용 상품+재고를 DB에 직접 삽입 (정적)
├── lib/
│   └── config.js                  # 공통: BASE_URL, 핫 productId 풀, 헬퍼
├── scenario1-lock-contention.js   # [Closed] PUT /v1/stocks — 락 경합
└── scenario2-stock-lookup.js      # [Open]   GET /v1/stocks/{id} — DB 부하
  • lib/config.js — 두 시나리오가 공유하는 상수(서버 주소, productId 목록)를 한 곳에서 관리하여 유지보수성을 용이하게한다.
  • 시나리오별 파일 분리 — 부하 모델(closed/open)과 executor 설정이 완전히 다르므로 각각 독립 실행
  • seed/seed.sql — 시딩을 코드(k6)와 분리, 테스트 전에 딱 한 번 실행하는 준비물

3. 수치화

 


참고 자료

1) Grafana Docs : Open and closed models

https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/open-vs-closed/

 

Open and closed models | Grafana k6 documentation

Open and closed models Different k6 executors have different ways of scheduling VUs. Some executors use the closed model, while the arrival-rate executors use the open model. In short, in the closed model, VU iterations start only when the last iteration f

grafana.com