<aside> <img src="/icons/reorder_gray.svg" alt="/icons/reorder_gray.svg" width="40px" />
목차
</aside>
<aside> ⚠️
문제상황
경매 메인 화면에서 호출되는 /api/v2/auctions/overview
API는
추천 옥션 + 일반 옥션 목록을 함께 반환하는 통합 API였다.
부하 테스트 결과, 다음 문제가 발생했다:
<aside> 📌
원인
원인 항목 | 상세 내용 |
---|---|
추천 경매 ID는 Redis에 있으나 상세 정보는 DB에서 조회 | → 추천 경매 ID는 빠르게 불러오지만, AuctionListItem 전체 정보는 다시 RDB에서 조회해야 했음 |
반복적인 currentPrice , bidCount 조회 |
각 경매마다 Redis에서 현재 가격과 입찰 수를 개별 조회 → N+1 성격의 Redis 요청 발생 |
정렬 + 페이징 + 추천 구분 로직 복잡 | 추천 목록과 일반 목록을 구분하여 반환하는 로직이 DB와 Redis를 모두 호출 |
캐싱 부재 | /overview 응답 자체를 캐시하지 않아 매번 모든 조회 로직 수행 |
</aside>
<aside> 🛠
문제해결
해결 방안 | 설명 | 최종 결정 |
---|---|---|
추천 경매 ID만 Redis → 상세 정보도 Redis화 고려 | AuctionListItem 일부 필드 Redis 저장 검토 |
보류 (1단계에선 ID만 활용) |
currentPrice , bidCount Redis Bulk 처리 |
N+1 Redis 요청 제거 → Pipeline 사용 고려 | ✅ 적용 |
overview API 자체 결과 캐싱 |
Group별 추천 결과 TTL 캐싱 → 반복 요청 방어 | ✅ 적용 |
DB 쿼리 조건 최적화 | IN (ids) 조건 + 인덱스 확인 |
✅ 적용 |
</aside>
<aside> ✅
적용
추천 목록 조회 로직
// Redis Sorted Set → 추천 Auction ID 상위 10개 조회
Set<String> redisIds = recommendRedisRepository.findTopAuctionIds(groupId, 10);
List<Long> recommendedIds = redisIds.stream().map(Long::valueOf).toList();
Redis 현재가격 & 입찰수 처리
// 각 auctionSeq에 대해 Redis 조회 (가능한 경우 pipeline 또는 캐시 로딩)
auctionList.forEach(a -> {
Long price = auctionRedisRepository.findCurrentPrice(a.getAuctionSeq());
Long bids = auctionRedisRepository.findBidCount(a.getAuctionSeq());
a.updateBidInfo(price, bids);
});
DB 조회 방식 개선
// AuctionListItem은 커스터마이징된 Projection으로 ID 기반 조회
auctionRepository.findListItemsByIds(recommendedIds);
캐싱 전략
// overview API 자체 결과는 캐싱하지 않되,
// 추천 대상 경매 목록만 Redis TTL 적용 (5분)
</aside>