이커머스 DB 스키마 구성 전략: Olist 사례 분석

들어가며

오늘은 이커머스 서비스에서 DB 스키마를 효과적으로 구성하는 전략에 대해 알아보겠습니다. 특히 브라질의 대표적인 이커머스 기업 Olist의 데이터셋을 통해 실제 운영 환경에서 사용되는 스키마를 살펴보고, 확장성과 성능 최적화를 위한 전략을 논의하겠습니다.

단순히 ‘이런 스키마가 정답이다’라는 식의 접근이 아닌, 실제 서비스가 성장하면서 어떻게 모놀리스에서 MSA로 전환해 나갈 수 있는지, 성능 병목을 어떻게 해결할 수 있는지에 초점을 맞추어 설명하겠습니다.

Olist 이커머스 데이터셋 개요

Olist 데이터셋은 브라질 최대 이커머스 마켓플레이스 중 하나인 Olist의 2016년부터 2018년까지 약 10만 건의 주문 데이터를 포함하고 있습니다. 이 데이터셋은 다음과 같은 9개의 관계형 테이블로 구성되어 있습니다:

  1. customers - 고객 정보
  2. geolocation - 우편번호별 지리적 위치 정보
  3. order_items - 주문에 포함된 아이템 정보
  4. order_payments - 주문 결제 정보
  5. order_reviews - 주문에 대한 고객 리뷰
  6. orders - 주문 메타데이터
  7. products - 상품 정보
  8. sellers - 판매자 정보
  9. product_category_name_translation - 상품 카테고리 번역 정보

이 테이블들은 고유 식별자를 통해 서로 연결되어 있어, 여러 관점에서 주문 정보를 조회할 수 있습니다. 데이터가 이렇게 여러 테이블로 분리된 이유와 이를 실무에 어떻게 적용할 수 있는지 살펴보겠습니다.

모놀리스에서 MSA로: 현실적인 접근

시작부터 모든 서비스가 MSA로 설계되는 경우는 거의 없습니다. 대부분 통합된 구조로 시작해서 사용자가 늘어나고 기능이 추가될수록 점진적으로 분리되는 형태를 띱니다. 이것이 “소프트웨어”라고 불리는 이유이기도 합니다.

이커머스의 MSA화 예시: 상품 서비스 분리

이커머스에서 가장 많은, 그리고 자주 조회되는 데이터는 바로 상품 데이터입니다. 상품 테이블에는:

  • 자주 노출되는 인기 상품
  • 빠르게 품절되는 상품과 재고 정보
  • 리뷰, 별점, 상세 이미지
  • 다국어 지원을 위한 번역 데이터

등 다양한 정보가 복합적으로 포함될 수밖에 없습니다.

실제 현업에서는 모놀리스에서 가장 먼저 상품 관련 테이블을 분리하는 경우가 많습니다. 이렇게 함으로써:

  1. 자주 조회되는 상품에 최적화된 트리거를 설정할 수 있음
  2. 나이키 신발 출시나 블랙프라이데이 같은 트래픽 폭증 시 상품 DB만 독립적으로 확장 가능
  3. 상품 정보 갱신과 조회에 대한 병목 현상 해소

이처럼 부하가 집중되는 서비스부터 점진적으로 분리하는 방식이 실무에서 더 현실적인 MSA 전환 전략입니다.

DB 컨벤션과 데이터 타입 선정의 중요성

팀 단위로 프로젝트를 진행할 때 가장 큰 문제 중 하나는 각자 다른 DB 명명 규칙과 데이터 타입을 사용하는 것입니다. 이는 나중에 코드를 병합할 때 심각한 갈등을 유발할 수 있습니다.

팀 컨벤션의 실제 적용 사례

우리 팀에서도 초기에 이러한 문제를 겪었지만, 다음과 같은 명확한 컨벤션을 정립함으로써 해결할 수 있었습니다:

1. ID 컬럼 명명 규칙

<엔터티명>_id 형태로 통일
예: product_id, customer_id, order_id

2. 시간 관련 컬럼 명명 규칙

  • 정확한 시각 정보: _at 접미사 사용 (예: created_at, updated_at)
  • 날짜만 필요한 경우: _date 접미사 사용 (예: delivery_date, birth_date)
  • 타임스탬프: _timestamp 접미사 사용 (이벤트 발생 순간)

3. 데이터 타입 선정 원칙

  • 연산이 필요한 숫자는 INT/DECIMAL 등 숫자형으로 저장
  • 코드값/분류값은 문자열(VARCHAR)로 저장
  • 날짜/시간은 목적에 맞게 DATE, DATETIME, TIMESTAMP 구분

이러한 컨벤션 덕분에 프로젝트 병합 시 불필요한 충돌이 크게 줄었고, 데이터베이스 구조에 대한 이해도 일관되게 유지할 수 있었습니다.

Redis를 활용한 API 성능 최적화

프론트엔드 개발을 하다 보면, 변경이 거의 없지만 매우 자주 호출되는 API가 있습니다. 예를 들어:

  • 카테고리 목록
  • 메인 페이지 배너
  • 공지사항
  • 자주 묻는 질문

이런 데이터는 하루에 한 번 정도 바뀔까 말까 한 정보들입니다. 이런 데이터를 매번 DB에서 조회하는 것은 비효율적입니다.

실제 캐싱 적용 사례

우리 서비스에서는 Redis를 활용해 이러한 정적 데이터를 캐싱했습니다:

1. 카테고리 데이터: Redis Hash 구조로 저장
2. 배너 정보: Redis Sorted Set으로 우선순위 관리
3. 위치 정보: 우편번호-좌표 매핑을 Redis에 저장

이를 통해 얻은 효과는 다음과 같습니다:

  • DB 쿼리 수 80% 감소
  • API 응답 시간 95% 단축
  • 트래픽 폭증 시에도 안정적인 서비스 제공

중요한 점은, 모든 사용자에게 동일한 데이터를 제공해야 하는 경우(카테고리, 공지사항 등)에는 Redis 캐싱이 특히 효과적이라는 것입니다.

정규화와 확장 가능한 스키마 설계

Olist 데이터셋에서 볼 수 있듯이, 주문 관련 데이터가 여러 테이블로 나뉘어 있습니다:

  • orders: 주문 기본 정보
  • order_items: 주문 포함 상품
  • order_payments: 결제 정보
  • order_reviews: 리뷰 정보

이러한 분리가 왜 중요한지 살펴보겠습니다.

정규화의 실무적 이점

  1. 데이터 중복 최소화: 같은 상품이 여러 주문에 포함되어도 상품 정보는 한 번만 저장
  2. 갱신 용이성: 상품 정보 변경 시 한 곳만 수정하면 됨
  3. 데이터 일관성: 업데이트 오류 및 불일치 방지
  4. 서비스별 분리 용이: MSA로 전환 시 자연스러운 서비스 경계 제공

예를 들어, 주문 서비스는 orders와 order_items 테이블을, 리뷰 서비스는 order_reviews 테이블을 각각 관리할 수 있습니다.

컬럼 설계 전략과 데이터 접근 패턴

효율적인 스키마 설계는 데이터 접근 패턴을 고려해야 합니다. Olist 데이터셋에서 볼 수 있는 전략은 다음과 같습니다:

1. 복합 속성의 세분화

상품의 크기를 하나의 JSON 필드로 저장하는 대신, product_length_cm, product_height_cm, product_width_cm로 분리해 개별 속성 검색과 필터링이 용이하게 합니다.

2. 의미 있는 분리

가격과 배송료를 pricefreight_value로 분리해, 순수 상품 매출과 물류비를 별도로 분석할 수 있게 합니다.

3. 참조 데이터의 외부화

상품 카테고리 번역을 별도 테이블로 분리해, 다국어 지원과 카테고리 체계 변경에 유연하게 대응할 수 있습니다.

결론: 실무에서의 스키마 설계

이커머스 DB 스키마 설계에 있어 핵심은 처음부터 완벽한 MSA를 목표로 하기보다, 서비스 성장에 맞춰 점진적으로 발전시키는 것입니다.

실무에서 적용할 수 있는 핵심 전략은 다음과 같습니다:

  1. 팀 컨벤션 확립: ID, 날짜/시간, 데이터 타입 등에 대한 명확한 규칙 수립
  2. 부하 집중 영역 식별: 상품, 주문 등 트래픽이 집중되는 영역부터 분리
  3. 캐싱 전략 적용: 자주 조회되지만 변경이 적은 데이터는 Redis로 캐싱
  4. 정규화와 성능의 균형: 완벽한 정규화보다는 실제 쿼리 패턴에 맞는 설계

기억해야 할 것은, 가장 좋은 스키마는 현재 비즈니스 요구사항을 충족하면서 미래의 변화에도 유연하게 대응할 수 있는 구조라는 것입니다.

처음부터 완벽한 설계를 목표로 하기보다는, 실제 운영 경험을 통해 지속적으로 개선해 나가는 접근법이 실무에서는 더 효과적인 전략입니다.

참고 자료