( 이전 글과 이어지는 포스트입니다. )
이전 시간까지 멀티 쓰레드, 멀티 서버 환경을 고려하여 동시성 문제 해결하기 위해 JPA의 @Lock을 사용해서 해결했고, Redisson 또한 적용해봤습니다. 그럼 이제 수행해야할 과제는 무엇인가.. 당연 서버의 성능, 내가 만든 API의 성능을 측정하는 것이였습니다. 저는 다양한 방법 중 Redis Cache를 사용하였고 tps를 42/sec -> 104/sec로 개선 시켜 보았습니다. 백엔드 단의 API 로직 구현이 전부인 프로젝트에서 어떤 기준으로 성능을 측정해야할까요? 실무에서는 모니터링 한 유저 트래픽 데이터를 바탕으로 시간 대별로 TPS 기준을 세운다고 하는데 그럼 제 프로젝트 환경에서는 성능 테스트의 의미가 없는 걸까요? 제한이 있긴 했지만 이러한 고민들을 가지고 일단 성능 테스트를 진행해봤습니다.
테스트는 멀티쓰레드 환경을 고려해서 Jmeter를 사용했습니다. (처음 사용)
성능 측정(개선 전)
테스트 시나리오
1000명의 사용자가 동시에 결제 진입을 한다.
설정 값
Number of Threads(users): 1000
Ramp-up period (seconds): 1
Loop Count: 1
결과
42.65/sec라는 수치가 나왔습니다. 1000개의 트랜잭션을 처리하는데 대략 21초가 걸리군요 최악의 경우 결제 시작 버튼을 누르고 21초가 지나야 결제 정보를 입력할 수 있다니.. 저라면 이 서비스를 이용하지 않을 것입니다.
TODO
저렇게 낮은 수치를 보고 Tps 개선에 대한 목표가 생겼습니다. 정확한 목표 수치는 설정하기 어려웠습니다. 일단 아는 선에서 최대한 개선 -> 답이 안나오면 새로운 기술 적용 해보기로 했습니다.
성능 개선 과정
결제 진입 플로우에서 성능 이슈 고민해보기
1. 유저가 결제 진입 API를 호출한다. -> 유저 테이블 email 문자 풀스캔 -> 인덱스 설정(적용✅ tps 아주 조금 향상)
2. 주문 서비스에서 주문 정보를 전부 가져온다. -> 주문 정보를 빠르게 조회하기 위해 NoSQL 사용하면 좋을거같음
3. 재고 서비스를 호출한다. -> 비동기적으로 해보면 좋을거 같음
4. 재고 수량 검증한다.
5. 재고 감소한다. -> 디스크 I/O 발생 -> DB 부하
- 재고 수량을 한번에 반영하는 방법이 없을까 -> 메시징 큐 카프카 써보면 좋을거같음
- 연산 속도를 빠르게 -> Redis Cache사용(적용✅)
아래 사진은 성능 개선 전(왼쪽) 개선 후 동시 요청 중 Disk 사용률에 대한 그래프입니다.
Redis 사용 이유(기술)
1. 메모리 기반의 빠른 I/O 처리
2. 원자성 보장 (INCR, DECR 명령어)
Redis 사용이유(도메인)
1. 상품 A는 특정 시간에 구매가 활성화 됨
2. 구매 시도자들은 1의 특정 시간에 몰려서 구매함
재고 감소 증가 비즈니스 로직(Redis 적용)
// Key -> PRODUCT:5, Value -> 10000(남은 수량)
public void decrementStock(Long productId, Integer quantity) {
String key = getKey(productId);
redisTemplate.opsForValue().decrement(key, quantity);
}
public void incrementStock(Long productId, Integer quantity) {
String key = getKey(productId);
redisTemplate.opsForValue().increment(key, quantity);
}
성능 측정(개선 후)
테스트 시나리오
1000명의 사용자가 동시에 결제 진입을 한다.
설정 값
Number of Threads(users): 1000
Ramp-up period (seconds): 1
Loop Count: 1
결과
tps가 105.72/sec 개선전과 비교해서 2배정도 올랐고 1000개의 트랜잭션을 처리하는데 21 -> 8초로 감소되었음을 볼 수 있습니다.
TODO
1. 테스트 툴과 백엔드 서버를 분리하여 정확하게 성능 측정하기
2. WebFlux와 같은 Non-Blocking 서비스를 사용하여, 비동기적으로 클라이언트 요청에 응답하는 방법 고려해보기
3. 적절한 커넥션 풀 개수 생각해보기 + 학습하기(maxPoolSize 조절해봤지만 차이가 없음)
4. MSA 더 공부하기.. 아직 잘 모르겠다.
'SideProject' 카테고리의 다른 글
스위프 5기 FADE 프로젝트 돌아보기 후기 (0) | 2024.08.12 |
---|---|
Sse 알림 기능 적용해보기 (Spring Boot) (0) | 2024.06.14 |
구매 서비스에서 재고 동시성 이슈 해결해보기(2) - Redisson (1) | 2024.02.28 |
구매 서비스에서 재고 동시성 이슈 해결해보기(1) - JPA LOCK (0) | 2024.02.26 |