중고차의 늪
최근 중고차에 관심이가 벤츠 인증 중고차 사이트를 자주 들락날락했다.
문제는 사이트에서 차량 조회하면 약 2초 이상 소요되어 이쁜 자동차들을 빠르게 구경하지 못해 고통받았다.
답답해서 사이트를 금방 탈주하게 되었고 개선이 필요해 보였다.
그에 비해 엔카는 86.55ms로 아주 훌륭한 조회 성능을 보여준다.
덕분에 엔카에 한번 접속하면 2시간은 순삭이다. 최적의 조회 성능으로 헤어나지 못하게 만든다.
이처럼 조회 성능은 매우중요하다. 2초 아니 1초만 소요되도 느리다고 생각해 사용자에게 좋지 않은 경험을 만들어준다.
조회 성능 개선 고민
지난 프로젝트에서 100만건의 상품데이터를 관리하며 발생되는 문제 중 상품 검색 조회 같은 경우 Elasticsearch를 적용하여 성능 개선하였고 단건 조회에서의 문제를 찾아봤다.
다행히 PK기반의 단건 조회는 인덱스 설정으로 RDB에서도 100~200ms의 Elasticsearch만큼 빠르지 않지만 양호한 조회 성능을 보여줬다.
이미 Elasticsearch를 사용 중이라 단건 조회도 함께 처리할 수 있지 않을까 생각했지만 모든 조회를 Elasticsearch로 통합하는 것이 맞을까 고민했다.
양호한 조회 성능 나오는 단건 조회에서 RDB와 Elasticserach간의 실시간 데이터 동기화 문제, 추가적인 운영 부담을 안고 사용할래? 묻는다면 오버엔지니어링일 수 있다 생각한다.
그래도 인기상품 같은 경우 사용자의 조회가 많아 성능 문제가 생길거라 생각했고 얼마나 차이가 있을지 트래픽이 몰리는 상황을 만들어 테스트를 진행했다.
인기 상품 조회 성능 테스트
초당 500번의 요청이 발생하는 상황에서의 인기 상품 단건 조회 테스트 진행
TPS 500
처리량: 32.9/sec
최소 응답 시간: 375ms
최대 응답 시간: 14407ms (약 14.4초)
평균 응답시간: 3938ms (약 3.9초)
성능에 심각한 문제가 보였다.
조회 성능을 위해 이미 인덱스를 적용해 더이상의 성능 개선 효과를 기대하긴 어려웠고 캐싱을 시도했다.
모든 상품을 캐싱하기에는 무리가 있었고 트래픽이 몰릴거라 예상되는 인기상품 TOP 10을 정해 캐싱하기로 결정
Log 작업
상품조회 수치를 집계하기 위해 Logstash 설정 후 상품 단건 조회 시 로그를 저장했다.
캐싱 스케줄러 로직 구현
@Transactional
public void refreshPopularProductsCache() {
TimeRange timeRangeForCache = schedulerUtil.getTimeRangeForCache();
List<LogDetails> logDetailsList = getLogsInTimeRange(timeRangeForCache);
Map<String, Integer> productIdAndViewCount = calculateProductViewCounts(logDetailsList);
saveCacheProduct(productIdAndViewCount);
}
1. 현재 시간부터 1시간 전 TimeRange 설정한다.
2. Logstash에서 TimeRange 시간대에 맞는 로그 조회
3. 조회된 로그 값에서 상품 아이디, 조회 수 계산
4. 인기 상품 Redis 캐싱
상품 단건 조회 캐시 적용
public ProductDetails findById(String productPublicId) {
log.info("publicId = {}", productPublicId);
ProductDetails cachedProduct = productOperations.get("getProduct:" + productPublicId);
if (cachedProduct != null) {
return cachedProduct;
}
return productRepository.findByProductAndCurrentPrice(productPublicId)
.orElseThrow(() -> new ProductException(
ErrorCode.PRODUCT_NOT_FOUND));
}
1. 캐시에서 데이터 확인 후 있으면 반환
2. 없으면 DB 조회
Look Aside 전략과는 비슷하지만 조금 다르다.
캐시에 데이터가 없다면 DB에서 조회 후 캐시 데이터를 저장 하지 않는다.
인기상품 캐싱 후 부하테스트
TPS:500
처리량: 238.1/sec
최소 응답 시간: 44ms
최대 응답 시간: 1719ms (약 1.7초)
평균 응답시간: 346.85ms (약 0.35초)
인기 상품 캐싱 전 후 비교
평균 응답시간이 3938ms -> 346.85ms
약 11.2배 상승했다.
전체 처리 소요시간은 15.2s -> 2.4s
약 6배 단축되었다.
'이슈' 카테고리의 다른 글
상품 재고 관리 - 비관적 락 vs 분산 락 적용 사례 (3) | 2025.01.31 |
---|---|
RDB vs Elasticsearch 검색 성능 비교 (1) | 2025.01.10 |
Kafka, Redis를 활용한 이벤트 중복 처리 방지 (2) | 2024.12.19 |
[Jenkins] 용량 부족 - EBS 볼륨 연결 (0) | 2024.11.19 |
AWS EC2 배포 작업 (0) | 2023.09.07 |