본문 바로가기
성능 개선

구매 요청에 대한 데이터베이스 부하 최적화

by 우 석 2024. 4. 25.

[문제 상황 & 원인]

  • 대량 구매 요청으로 인해 빈번한 데이터베이스 쓰기가 발생하여 데이터베이스 리소스에 부담을 줍니다.
  • 또한 각 구매 요청은 데이터베이스 쓰기 작업을 트리거하여 제품 수량을 업데이트하므로 데이터베이스 트랜잭션의 양이 많아집니다.

[해결 과정]

  • 인메모리 데이터 구조 저장소인 Redis를 활용하여 제품 수량을 관리합니다.
    • 구매 요청이 있을 때마다 데이터베이스를 즉시 업데이트하지 않고, Redis에서 상품 재고를 관리하여 상품의 수량을 감소합니다.
    • Redis의 제품 수량이 0에 도달하여 제품이 품절되었음을 나타내는 경우에만 데이터베이스에 쓰는 메커니즘을 구현했습니다. 

 

상품을 DB에 등록하는 과정에서 hashOperations.put() 메서드로 redis의 해시 맵에 데이터를 추가합니다.

@Override
@Transactional
public void createProduct(ProductCreateRequestDto productCreateRequestDto,
    Long userId) {
    userService.validateAdminUser(userId);
    Product product = Product.createOf(productCreateRequestDto);
    Product saveProduct = productRepository.save(product);

    hashOperations.put(HASH_KEY, String.valueOf(saveProduct.getId()),
        String.valueOf(saveProduct.getAmount()));
}

 

 

redis에 상품 id와 상품 수량 등록

 

 

구매 요청이 들어오면 아래 메서드가 수행되어, redis의 상품 수량을 차감합니다.

이후 상품 수량이 0이 되면 redis의 데이터를 삭제하고, 연동된 DB의 상품 수량을 변경 후, 판매완료 상태로 업데이트합니다.

// 상품 수량 차감 메서드
private void deductProductAmount(Product product) {

  if (!hashOperations.hasKey(HASH_KEY, String.valueOf(product.getId()))) {
      throw new IllegalArgumentException("재고가 소진되었습니다.");
  }

  long incrementCount = hashOperations.increment(HASH_KEY,
      String.valueOf(product.getId()), -1);

  if (incrementCount == 0) {
      hashOperations.delete(HASH_KEY, String.valueOf(product.getId()));
      product.updateAmount(0);
      product.softDelete();
  }
}

 

 

Redis에서 상품 제고를 관리하기 때문에 기존 데이터베이스 보다 처리 속도가 빠르고, 데이터베이스 쓰기를 연기함으로써 데이터베이스 트랜잭션 수를 최소화하여 데이터베이스 서버의 부담을 완화할 수 있었습니다.

'성능 개선' 카테고리의 다른 글

DB replication  (0) 2024.05.08
Caching  (0) 2024.05.08
Indexing  (0) 2024.05.08