새소식

Welcome to the tech blog of Junior Backend Developer Seulbin Kang!

Project

[Sansam E-commerce] 3. MVP 이후 리팩토링 #1 : 재고 도메인 ERD 분리 과정

  • -

👀 들어가기 전에

 

ERD를 설계한 뒤, 애자일하게 시작하기 위해 API 명세를 Swagger로 먼저 빠르게 작성하고 MVP 개발에 바로 들어갔던 기억이 난다.

일정이 빠듯했기 때문에 "일단 MVP를 시간 내에 완성하는 것"이 최우선 목표였고, 구조적인 개선이나 리팩토링은 MVP 이후 단계에서 진행하기로 결정했다. 

그래서 이전 글과 이 글까지의 중간 과정이 다소 많이 생략되어있다. (그 시점에서는 정말 숨 돌릴 틈이 없었다... 🙏)


👀 본론 : 재고 ERD 분리 과정

 

MVP 단계에서는 재고 정보는 product_detail 테이블에 포함된 형태로 관리되고 있었다.

기능적으로는 문제가 없었지만, 개발을 진행하면서 점점 한 가지 의문이 들었다.

재고 데이터와 상품 데이터가 정말 같은 라이프사이클을 가져도 되는 걸까?

 

결론부터 말하자면, 그렇지 않다고 판단했다.


문제 인식 : 데이터의 라이프사이클이 다르다.

상품 정보와 재고 정보는 성격이 완전히 다르다.

  • 상품 정보
    • 이름, 가격, 설명 등
    • 변경 주기가 비교적 길다
    • 대부분 조회 (Read) 중심이다.
  • 재고 정보
    • 주문 트래픽에 따라 수시로 변경
    • 거의 모든 주문 요청마다 UPDATE 발생
    • 쓰기 (Write) 중심 데이터이다.

이 두 데이터를 하나의 테이블에서 함께 관리할 경우 다음과 같은 문제가 발생할 가능성이 높다고 판단했다.


 

문제 1. 쓰기 경합 증가

 

재고 차감은 주문 요청마다 발생한다.

만약 상품 정보와 재고 정보가 동일 테이블에 있다면

  • 재고 UPDATE 시 row-level lock이 발생한다.
  • 동시에 상품 조회/다른 재고 차감 요청이 몰릴 경우
  • 락 경합이 빠르게 증가한다.

특히 InnoDB 환경에서는 쓰기 트래픽이 몰릴수록 전체 처리량에 영향을 줄 수 있다.


문제 2. InnoDB Buffer Pool 효율 저하

 

재고 수량이 변경될 때마다

  • 더티 페이지가 생성되고
  • 해당 페이지가 반복적으로 갱신된다.

이때 상품 정보까지 포함된 테이블이라면,

  • 버퍼 풀 내 페이지 교체가 잦아지고
  • 캐시 효율이 떨어질 가능성이 커진다.

즉, 재고 UPDATE 하나 때문에 상품 조회 성능까지 간접적인 영향을 받을 수 있는 구조였다.


문제3. 인덱스 페이지 오염 가능성

 

재고 수량 변경은 인덱스 리프 페이지에도 영향을 준다.

  • 조회(Read)와 갱신(Update)이 동일 인덱스를 공유할 경우
  • 불필요한 인덱스 페이지 수정이 발생하며
  • 결국 조회 성능까지 영향을 줄 수 있다.

이 역시 규모가 커질수록 체감되는 문제이다.


설계 결정 : 책임 분리

이러한 문제를 완화하기 위해, 재고 테이블을 별도로 분리하는 방향으로 설계를 수정했다.

핵심 원칙은 단순하다.

읽기 중심 데이터와 쓰기 중심 데이터를 분리하자

 

분리된 역할

 

Product 테이블

  • 상품의 고유 정보 관리
  • 조회(Read) 중심
  • 변경 빈도 낮음
  • 상품 검색 및 노출 성능에 집중

 

Stock 테이블

  • 상품별 재고 수량 관리
  • 쓰기(Update) 중심
  • 주문 트래픽에 직접 영향
  • 재고 차감/증가 로직을 최소 단위로 격리


 

👀 결론

이렇게 역할을 분리함으로써 재고 Update가 상품 조회에 미치는 영향을 최소화할 수 있으며 락 경합 범위를 재고 테이블로 국한시키며 각 테이블이 자신의 책임에만 집중할 수 있는 구조를 만들고자 했다. (추후, MSA구조로 분리가 된다고 생각해서도 적합한 선택이었다.)

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.