5편까지 Redis 동시성 제어와 Kafka 비동기 처리를 구현했다. 이번 편에서는 k6를 사용해서 실제로 동시 주문이 들어왔을 때 재고가 정확히 차감되는지 성능 테스트로 검증했다.
k6는 JavaScript로 테스트 스크립트를 작성할 수 있는 오픈소스 성능 테스트 툴이다. Postman처럼 API를 호출하는데, 동시에 수백 명이 요청하는 상황을 시뮬레이션할 수 있다.
brew install k6
목표: 재고 100개인 상품에 200명이 동시에 주문했을 때, 100건만 성공하고 나머지는 재고 부족으로 차단되는지 검증
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 200, // 동시 사용자 200명
duration: '10s', // 10초 동안
};
export default function () {
const token = 'Bearer {JWT토큰}';
const payload = JSON.stringify({
productId: 2,
quantity: 1,
});
const params = {
headers: {
'Content-Type': 'application/json',
'Authorization': token,
},
};
const res = http.post('http://localhost:8080/order', payload, params);
check(res, {
'주문 성공 (201)': (r) => r.status === 201,
'재고 부족 (400)': (r) => r.status === 400,
});
sleep(1);
}
동시 사용자: 200명
재고: 100개
총 요청: 2000건
주문 성공 (201): 100건 ✅
재고 부족 (400): 1802건 ✅
평균 응답 시간: 54ms
최대 응답 시간: 689ms
처리량: 182건/s
200명이 동시에 요청했지만 딱 100건만 성공했다. 재고를 초과한 주문은 0건.
// StockService.java
public Long decreaseStock(Long productId, int quantity) {
String key = "stock:" + productId;
return redisTemplate.opsForValue().increment(key, -quantity);
}
public Long increaseStock(Long productId, int quantity) {
String key = "stock:" + productId;
return redisTemplate.opsForValue().increment(key, quantity);
}
// OrderServiceImpl.java
Long remainStock = stockService.decreaseStock(
createOrderRequestDTO.getProductId(), createOrderRequestDTO.getQuantity()
);
// 재고 부족 체크
if (remainStock < 0) {
stockService.increaseStock(createOrderRequestDTO.getProductId(), createOrderRequestDTO.getQuantity());
throw new IllegalArgumentException("재고가 부족합니다.");
}
Redis의 increment 연산은 원자적(Atomic)으로 동작하기 때문에 동시에 여러 요청이 들어와도 정확하게 재고가 차감된다.
DB에서 재고를 읽고 차감하는 방식은 아래와 같은 문제가 생긴다.
Thread A: 재고 조회 → 5개 남음
Thread B: 재고 조회 → 5개 남음 ← A가 차감하기 전에 읽음
Thread A: 재고 차감 → 4개
Thread B: 재고 차감 → 4개 ← 실제론 3개여야 하는데!
이런 Race Condition을 Redis의 원자적 연산으로 해결했다.
k6 성능 테스트를 통해 Redis 동시성 제어가 실제로 동작함을 검증했다.
5편에 걸쳐 DCommerce 프로젝트를 완성했다.
1편 - Entity 설계 + 회원가입
2편 - JWT 로그인
3편 - 상품 + 주문 API
4편 - Redis 동시성 제어
5편 - Kafka 비동기 이벤트
6편 - k6 성능 테스트 (현재)
처음에는 운영 업무만 하다 보니 직접 구조를 짜가며 해볼 기회가 많이 없었는데, 이번 프로젝트를 통해 Spring Boot + Redis + Kafka 조합을 직접 설계하고 구현하며 찍먹해볼 수 있었다.