상품 단건 조회 - ekdan38/HotDealService GitHub Wiki
- CPU : Intel i5-8250U 1.6GHz
- RAM : 8GB
- OS : Window10
- Databse : MySQL 8.0
- Test Tool : K6
테스트를 위해 1만개의 핫딜, 10만개의 상품에 대한 더미 데이터를 생성하였다.
테스트 시나리오
상품 랜덤 조회
개선 전 k6 테스트
k6 테스트 결과
-
VU 100
-
VU 200
-
VU 300
상품 단건 조회 (3분) | 총 처리량 | Latency(mean) | Latency(P95) | TPS |
---|---|---|---|---|
VU 100 | 52905 | 338ms | 608ms | 293 |
VU 200 | 50923 | 706ms | 1.26s | 281 |
VU 300 | 52997 | 1.02s | 2.3s | 292 |
테스트 결과 분석
- VU 100 -> 200 증가시, Latency(mean), Latency(P95) 모두 2배 증가
- TPS 증가가 거의 없음 준수한 성능을 보이고 있지만, 성능 개선 여지는 존재 성능 개선 계획
- DTO Projection : 단건 ROW를 조회하기에 DTO Projection은 생략
- 인덱싱 : 조회 성능 향상을 위해 적절한 인덱스를 생성하여 쿼리 탐색 비용 감소
- 캐싱: 반복적으로 조회되는 데이터를 캐시에 저장하여 DB 부하를 줄여 성능 개선
[실행계획]
EXPLAIN SELECT hdp.product_id,hdp.hotdeal_id,hdp.price,hdp.title
FROM hot_deal_product hdp
JOIN hot_deal hd ON hd.hotdeal_id=hdp.hotdeal_id
WHERE hdp.product_id=90302
AND hd.status='ACTIVE'
AND hd.deleted=0;
- hot_deal, hot_deal_product 테이블 모두 PK 클러스터링 인덱스 사용중
- (product_id, status, deleted) 를 WHERE 절에서 사용중
- status, deleted 의 카디널리티는 각각 4, 2로 낮아 복합 인덱스는 생성 필요 없음
- 현재 실행계획이 최적으로 판단, 따라서 인덱싱은 진행하지 않음
캐싱을 통해 DB에 직접 접근하는 대신, In-Memory 수준에서 빠르게 데이터 I/O 처리를 수행함으로써 응답 속도 향상 및 부하 감소 등 성능 개선 효과 기대
3.1. 캐싱 적용
private ProductSimpleDto getProductAndValidate(Long productId) {
// 1. Redis 캐시 조회
ProductCacheDto cachedData = productRedisRepository.getProductById(productId);
if(cachedData != null){
return new ProductSimpleDto(cachedData);
}
// 2. CacheMiss -> DB 조회
ProductSimpleDto product = hotDealProductRepository.findActiveProductById(productId).orElseThrow(() -> {
log.debug("요청된 핫딜 상품이 존재하지 않습니다. hotDealProductId = {}", productId);
return new HotDealProductException(ErrorCode.HOTDEAL_PRODUCT_NOT_FOUND, productId);
});
// 3. Redis 에 캐시 저장
ProductCacheDto cacheDto = new ProductCacheDto(product);
productRedisRepository.saveWithTTL(cacheDto);
return product;
}
CacheAside를 사용하여 Redis 캐싱 적용
- 핫딜은 자주 변경되는 데이터가 아니라고 판단, TTL 30분 적용
- 일관성을 위해 상품에 대한 수정 삭제 발생시 캐시 무효화 처리(@CacheEvict)
캐싱 적용 후 k6 테스트
k6 테스트 결과
-
VU 100
-
VU 200
-
VU 300
상품 단건 조회 (3분) | 총 처리량 | Latency(mean) | Latency(P95) | TPS |
---|---|---|---|---|
VU 100 | 62089 | 288ms | 558ms | 344 |
VU 200 | 85216 | 421ms | 1.35s | 420 |
VU 300 | 112590 | 478ms | 1.23s | 624 |
분석
Latency
-
Latency(mean)
- VU 100: 338ms → 288ms (약 14.8% 개선)
- VU 200: 706ms → 421ms (약 40.4% 개선)
- VU 300: 1.02s → 478ms (약 53.1% 개선) Latency(mean) : 전 구간 감소했으며, VU가 증가할수록 점점 상승 곡선을 나타냄
-
Latency(P95)
- VU 100: 608ms → 558ms (약 8.2% 개선)
- VU 200: 1.26s → 1.35s (약 7.1% 악화)
- VU 300: 2.30s → 1.23s (약 46.5% 개선) Latency(P95) : 전반적으로 개선되었으며, 특히 VU 300 에서 절반 가까이 개선됨. 다만 VU 200 에서는 일부 요청에서 CacheMiss 또는 순간 부하로 인해 지연 시간이 소폭 증가하는 현상 발생
TPS
- VU 100: 293 → 344 (약 17.4% 증가)
- VU 200: 281 → 420 (약 49.5% 증가)
- VU 300: 292 → 624 (약 113.7% 증가)
TPS : VU가 증가할수록 큰 상승 곡선을 나타내며, VU 300에서는 2배 이상 증가
캐싱을 적용했지만, 기대치와 달리 개선 수치가 낮음
10만개의 상품에 대한 조회를 하기 때문에 CacheHit 비율이 낮아 고부하 구간일수록 큰 상승폭으로 성능이 증가하는 모습을 보임 => 실제 서비스 환경에서는 핫딜 이벤트 기간에 10만개의 데이터에 대한 조회가 없기에 현재보다 성능이 좋을것으로 예상
항목(각 개선 단계는 이전 단계 포함) | 캐싱 적용 |
---|---|
평균 Latency 감소율 | 약 15 ~ 53% |
TPS 증가율 | 약 17 ~ 113% |
- 단일 Row 조회이기 때문에 DTO Projection 적용 하지 않음
- 인덱싱 또한 현재 실행 계획이 효율적이기에 진행하지 않음
- 캐싱으로 인한 성능 개선이 기대와는 다르게 낮은 수치를 나타냄
- 상품에 대한 더미 데이터 10만건을 대상으로 진행한 테스트이기 때문에 VU 가 커질수록 CacheHit 비율이 증가하여 성능이 크게 향상되는 모습을 보임
- 실제 서비스 환경에서는 핫딜 이벤트 기간에 10만개의 데이터에 대한 조회가 없기에 현재보다 성능이 좋을것으로 예상