상품 단건 조회 - ekdan38/HotDealService GitHub Wiki

테스트 환경

  • CPU : Intel i5-8250U 1.6GHz
  • RAM : 8GB
  • OS : Window10
  • Databse : MySQL 8.0
  • Test Tool : K6

상품 조회 성능 최적화 및 k6 테스트 비교

테스트를 위해 1만개의 핫딜, 10만개의 상품에 대한 더미 데이터를 생성하였다.

상품 단건조회

테스트 시나리오

상품 랜덤 조회

개선 전 k6 테스트

k6 테스트 결과
  • VU 100
    VU100 결과
  • VU 200
    VU200 결과
  • VU 300
    VU300 결과
상품 단건 조회 (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 증가가 거의 없음 ​ 준수한 성능을 보이고 있지만, 성능 개선 여지는 존재 ​ 성능 개선 계획
  1. DTO Projection : 단건 ROW를 조회하기에 DTO Projection은 생략
  2. 인덱싱 : 조회 성능 향상을 위해 적절한 인덱스를 생성하여 쿼리 탐색 비용 감소
  3. 캐싱: 반복적으로 조회되는 데이터를 캐시에 저장하여 DB 부하를 줄여 성능 개선

성능 개선

1. 인덱싱

[실행계획]

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;

Image

  • hot_deal, hot_deal_product 테이블 모두 PK 클러스터링 인덱스 사용중
  • (product_id, status, deleted) 를 WHERE 절에서 사용중
    • status, deleted 의 카디널리티는 각각 4, 2로 낮아 복합 인덱스는 생성 필요 없음
  • 현재 실행계획이 최적으로 판단, 따라서 인덱싱은 진행하지 않음

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
    VU100 결과
  • VU 200
    VU200 결과
  • VU 300
    VU300 결과
상품 단건 조회 (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만개의 데이터에 대한 조회가 없기에 현재보다 성능이 좋을것으로 예상


3. 상품 단건 조회 성능 개선 최종 정리

항목(각 개선 단계는 이전 단계 포함) 캐싱 적용
평균 Latency 감소율 15 ~ 53%
TPS 증가율 17 ~ 113%
  • 단일 Row 조회이기 때문에 DTO Projection 적용 하지 않음
  • 인덱싱 또한 현재 실행 계획이 효율적이기에 진행하지 않음
  • 캐싱으로 인한 성능 개선이 기대와는 다르게 낮은 수치를 나타냄
    • 상품에 대한 더미 데이터 10만건을 대상으로 진행한 테스트이기 때문에 VU 가 커질수록 CacheHit 비율이 증가하여 성능이 크게 향상되는 모습을 보임
    • 실제 서비스 환경에서는 핫딜 이벤트 기간에 10만개의 데이터에 대한 조회가 없기에 현재보다 성능이 좋을것으로 예상
⚠️ **GitHub.com Fallback** ⚠️