핫딜 단건 조회 - 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 49632 361ms 642ms 275
VU 200 51208 702ms 1.29s 283
VU 300 52151 1.03s 2.34s 288

테스트 결과 분석

  • VU 100 -> 200 증가시, Latency(mean), Latency(P95) 모두 2배 이상 증가
  • VU 200 수준에서 시스템 처리량 한계에 근접
  • TPS 증가가 거의 없음

단건 Row 조회이기 때문에 전반적인 성능이 나쁘지 않지만, DTO Projection, 인덱싱, 캐싱으로 성능 개선 시도

성능 개선 계획

  1. DTO Projection : 단건 ROW를 조회 하지만, 단건 Row도 필요한 필드를 조회하면 성능이 개선되는지 확인
  2. 인덱싱 : WHERE 조건으로 (deleted, hotdeal_id) 를 사용중 -> deleted 의 카디널리티는 2로, 기존 PK 클러스터링 인덱스 사용
  3. 캐싱: 반복적으로 조회되는 데이터를 캐시에 저장하여 DB 부하를 줄여 성능 개선

성능 개선

1. DTO Projection 적용

단건 Row 조회이지만, DTO Projection을 통해 필요한 필드만 선택적으로 조회할때 성능 향상이 있는지 확인하기 위해 적용

수정 전 

    @Query("SELECT h " +
            "FROM HotDeal h " +
            "WHERE h.deleted = false " +
            "AND h.id = :hotDealId")
    Optional<HotDeal> findHotDealById(@Param("hotDealId") Long hotDealId);

수정 후

    @Query("SELECT new com.hong.hotdealservice.dto.projection.HotDealSimpleDto" +
            "(h.id, h.title, h.description, h.startTime, h.endTime) " +
            "FROM HotDeal h " +
            "WHERE h.deleted = false " +
            "AND h.id = :hotDealId")
    Optional<HotDealSimpleDto> findHotDealById(@Param("hotDealId") Long hotDealId);

DTO Projection 반영 후 k6 테스트

k6 테스트 결과
  • VU 100
    VU100 결과
  • VU 200
    VU200 결과
  • VU 300
    VU300 결과
핫딜 단건 조회 (3분) 총 처리량 Latency(mean) Latency(P95) TPS
VU 100 51967 345ms 599ms 288
VU 200 51819 694ms 1.28s 287
VU 300 50847 1.06s 2.36s 281

테스트 결과 분석

Latency

  • Latency(mean)
    • VU 100: 361ms → 345ms (약 4.4% 개선)
    • VU 200: 702ms → 694ms (약 1.1% 개선)
    • VU 300: 1.03s → 1.06s (약 2.9% 악화)

Latency(mean) : 개선 전과 성능이 같음

  • Latency(P95)
    • VU 100: 642ms → 599ms (약 6.7% 개선)
    • VU 200: 1.29s → 1.28s (약 0.8% 개선)
    • VU 300: 2.34s → 2.36s (약 0.9% 악화)

Latency(P95) : 개선 전과 성능이 같음

TPS

  • VU 100: 275 → 288 (약 4.7% 증가)
  • VU 200: 283 → 287 (약 1.4% 증가)
  • VU 300: 288 → 281 (약 2.4% 감소)

TPS : 개선 전과 성능이 같음

개선되거나 악화되는 모습이 보기니하나 이는 테스트마다 결과에 대한 편차가 있는점을 고려하면 Latency, TPS 모두 개선 전과 성능이 같다고 볼 수 있음

1개의 Row 만 가져오기 때문에 효과가 미비하거나 DTO 변환 비용에 대한 오버헤드 발생


2. 인덱싱

[실행 계획]

EXPLAIN SELECT h.hotdeal_id, h.title, h.description, h.start_time, h.end_time
        FROM hot_deal h
        WHERE h.deleted = false
        AND h.hotdeal_id = 8300

Image

PK 클러스터링 인덱스를 타고 있고, ref : const, Extra : null 로 조건문이 단순하여 이미 효율적이라 판단하여 인덱싱 진행하지 않음


3. 캐싱

캐싱을 통해 DB에 직접 접근하는 대신, In-Memory 수준에서 빠르게 데이터 I/O 처리를 수행함으로써 응답 속도 향상 및 부하 감소 등 성능 개선 효과를 기대

3.1. 캐싱 적용

    private HotDealSimpleDto getHotDealAndValidate(Long hotDealId){
        // 1. Redis 조회
        HotDealCacheDto cachedData = hotDealRedisRepository.findById(hotDealId);
        if(cachedData != null){
            return new HotDealSimpleDto(cachedData);
        }

        // 2. cacheMiss -> DB 조회
        HotDealSimpleDto hotDeal = hotDealRepository.findHotDealById(hotDealId).orElseThrow(() -> {
            log.debug("요청된 핫딜이 존재하지 않습니다. hotDealId = {}", hotDealId);
            return new HotDealException(ErrorCode.HOTDEAL_NOT_FOUND, hotDealId);
        });

        // 3. Redis save
        HotDealCacheDto cacheDto = new HotDealCacheDto(hotDeal);
        hotDealRedisRepository.saveWithTTL(cacheDto);

        return hotDeal;
    }

CacheAside 방식을 사용하여 Redis 캐싱 적용

  • 핫딜은 자주 변경되는 데이터가 아니라고 판단, TTL 30분 적용
  • 일관성을 위해 핫딜에 대한 수정 삭제 발생시 캐시 무효화 처리 캐싱 적용 후 k6 테스트 결과
k6 테스트 결과
  • VU 100
    VU100 결과
  • VU 200
    VU200 결과
  • VU 300
    VU300 결과
핫딜 단건 조회 (3분) 총 처리량 Latency(mean) Latency(P95) TPS
VU 100 120127 148ms 297ms 666
VU 200 136463 262ms 523ms 756
VU 300 133888 401ms 823ms 742

테스트 결과 분석

Latency

  • Latency(mean)
    • VU 100: 361ms → 148ms (약 59.0% 개선)
    • VU 200: 702ms → 262ms (약 62.7% 개선)
    • VU 300: 1.03s → 401ms (약 61.1% 개선)

Latency(mean) : 전 구간에서 약 60% 이상 개선

  • Latency(P95)
    • VU 100: 642ms → 297ms (약 53.7% 개선)
    • VU 200: 1.29s → 523ms (약 59.5% 개선)
    • VU 300: 2.34s → 823ms (약 64.8% 개선)

Latency(P95) : 약 54 ~ 65% 개선, 절반 이상 개선

TPS

  • VU 100: 275 → 666 (약 142.2% 증가)
  • VU 200: 283 → 756 (약 167.0% 증가)
  • VU 300: 288 → 742 (약 157.6% 증가)

TPS : 약 142 ~ 167% 개선, 최대 2.5배 증가

캐싱을 통해 Latency가 모든 구간 절반 이상 개선되었으며, TPS는 약 142 ~ 167% 개선, 최대 2.5배 향상


4. 핫딜 단건 조회 성능 개선 최종 정리 

항목 DTO Projection 캐싱 적용
평균 Latency 감소율 거의 없음(개선전과 동일) 약 60%
TPS 증가율 거의 없음(개선전과 동일) 142 ~ 167%
  • DTO Projection으로 인한 성능 개선 효과 없음
  • 인덱스를 통한 성능 개선은 현재 실행 계획이 효율적, 따라서 인덱스 생성하지 않음
  • Redis 캐싱 적용을 통해 눈에 띠는 성능 향상을 보임
⚠️ **GitHub.com Fallback** ⚠️