Home 비회원 최근 본 상품 기능 설계하기
Post
Cancel

비회원 최근 본 상품 기능 설계하기

이커머스 서비스에서 사용자는 상품을 둘러보며 쇼핑을 하게 된다. 옷이나 화장품, 신발 등 구매하고 싶은 카테고리가 있고 브랜드가 다양한 경우에 둘러본 상품들을 비교해서 구매한다.

또한, 상품을 둘러 보다가 방금 본 상품이 좀 더 마음에 들거나 가격이 궁금한 경우 봤던 상품을 다시 보고 싶어진다. 이를 위해 이커머스 플랫폼에서는 사용자가 봤던 상품들을 편하게 확인할 수 있게 최근 본 상품 기능을 제공한다.

현재 몇몇 플랫폼을 제외하고는 비회원에게도 최근 본 상품 기능을 제공하고 있다. 비회원 최근 본 상품 기능은 사용자에게 쇼핑의 연결성을 개선시켜 줄 수 있는 기능이다.

이번 포스팅에서는 비회원 최근 본 상품 기능 확장을 설계해본다.

설계 과정은 “가상 면접 사례로 배우는 대규모 시스템 설계 기초”의 설계 과정과 유사하게 구성해 보았다.

문제 이해 및 설계 범위 확정

최근 본 상품 기능을 비회원 대상으로 확장 설계를 위해 현재 서비스에서 확인할 수 있는 부분을 정리해보자.

  • 현재는 로그인 사용자에게만 최근 본 상품이 제공된다.
  • 약 5분에 3만건의 최근 본 상품이 저장된다.
  • 약 5분에 5만건의 상품 상세 진입 API가 호출된다.
  • 서비스에서는 이미 비회원 식별자를 사용하고 있다. 쿠키에 있는 non-login-id를 사용한다.
  • non-login-id 길이는 회원번호보다 길다.

이제 비회원 최근 본 상품 기능을 위한 조건을 확인해보자.

  • 사용자는 로그인이 되어 있지 않은 상태에서 최근 본 상품을 확인할 수 있어야 한다.
  • 비회원 식별자는 기기별, 브라우저별로 고유한 값을 가진다.
  • 상품 상세 페이지에 진입하게 되면 최근 본 상품에 저장된다.
  • 비회원 최근 본 상품은 30일 동안 유지 되어야 한다.
  • 상품 정보 하나를 노출하기 위해 필요한 값의 크기는 1KB이다.
  • 비 로그인 상태에서 상품 상세에 진입하는 요청은 약 5분에 2만건 정도 된다.
  • 로그인을 하게 되면 비 로그인 상태에서 봤던 최근 본 상품은 모두 로그인한 계정에 통합 된다.
  • 통합된 비회원 최근 본 상품은 즉시 삭제되어야 한다.
  • 통합될 때 동일한 상품이 있는 경우 마지막으로 본 시간이 업데이트 된다.
  • 로그인 로직이 복잡하기 때문에 최근 본 상품 통합은 로그인 로직에 영향을 주지 않아야 한다.

개략적 설계 및 상세 설계

비회원 최근 본 상품 기능을 제공하기 위해 필요한 것을 확인해본다.

식별자

우선 비회원을 식별할 수 있는 값이 필요하다. 서비스 내에 비회원 식별자가 없다면 UUID나 ULID 등으로 사용할 수 있지만, non-login-id 값을 비회원 식별자로 사용하고 있으므로 비회원 식별자는 쿠키에 non-login-id 값을 사용한다.

최근 본 상품 저장 방식

비회원의 최근 본 상품을 저장하는 방식에 대해 고민해 볼 수 있다. 두 가지 방법을 고민해 보자.

클라이언트 저장소에 저장

비 로그인 상태에서 최근 본 상품을 브라우저 저장소에 저장할 수 있다. 설계 조건을 고려한다면 Local storage나 Cookie에 저장해서 관리할 수 있다.

항목Local StorageCookie
저장 공간5~10MB최대 4KB
TTL 여부NY
데이터 유지YY
API 호출 시 포함 여부NY

Local Storage를 사용한다면 비회원 최근 본 상품 유지 기간인 30일을 직접 처리해 줘야 한다. 저장 공간은 최대 10MB로 최근 본 상품 최대 개수인 100개를 관리하기에는 문제는 없다.

Cookie를 사용한다면 저장 공간이 4KB이기 때문에 최대 개수인 100개를 저장할 수 없다. 상품 하나에 1KB가 필요하기 때문이다. 또한, Cookie에 저장되는 값은 API 호출 시에 헤더에 포함되어 요청 되기 때문에 다른 API 호출에도 최근 본 상품 정보가 담겨 요청된다.

RDB에 저장

데이터베이스에 저장하는 방식은 기존의 최근 본 상품 테이블과 동일한 속성을 가지고 식별자의 길이에만 차이가 있다.

non-login-id 값의 길이는 회원번호보다 길다는 점을 점을 고려하면 기존 테이블의 회원 번호 속성 길이를 늘려 사용하거나 비회원 최근 본 상품용 테이블을 별도로 생성해서 사용할 수 있다. 비회원 최근 본 상품은 로그인을 하지 않으면 garbage data가 되기 때문에 주기적으로 지워주는 것이 좋다.

최근 본 상품의 저장 방식에 대해 정리해본 결과 RDB에 데이터를 저장하는 것이 적합해 보인다.

최근 본 상품 통합하기

로그인이 성공하게 되면 즉시 비 로그인 상태에서 봤던 최근 본 상품이 통합되어야 한다. 로그인 로직에 영향을 주지 않고 데이터를 처리할 수 있는 방법을 고민해본다.

Kafka를 이용한 비동기 처리

로그인이 성공한 후 로그인 이력을 저장하는 API 내에서 회원 번호와 비회원 식별자를 Kafka topic으로 메시지를 발행한다. 최근 본 상품 외에도 찜, 장바구니 등 비회원 기능 확장을 고려하면 Kafka를 이용한 데이터 통합 방식이 적절하다.

API 호출로 데이터를 통합할 수 있지만, 로그인 트래픽이 몰리는 상황을 가정해보면 데이터 통합에 지연이 발생하면 로그인 이력 저장에도 영향을 줄 수 있다. 따라서, Kafka를 이용한 통합 방식이 트래픽이 급증하는 상황에서도 안정적으로 처리할 수 있다.

비회원 최근 본 상품 통합 프로세스

recent

비 로그인 상태에서 최근 본 상품이 저장되고 로그인 계정에 통합되는 과정을 간략하게 UML로 그려 보았다. 로그인 과정과 로그인 이력을 저장하는 과정은 생략했다.

MSA 아키텍처 기반으로 최근 본 상품 모듈과 로그인 모듈을 분리해서 표현하였고, 데이터베이스, Kafka를 모듈로 표현했다. 비회원 식별자는 쿠키에 저장되는 기기별, 브라우저별 고유한 값이기 때문에 데이터가 통합된 이후에는 비회원 최근 본 상품 테이블에서 데이터를 삭제해야 한다.

정리

이번 포스팅에서는 최근 본 상품 기능을 비회원으로 확장하는 설계를 해보았다. 설계하면서 중요하게 생각한 점은 비회원 최근 본 상품 데이터를 효율적으로 관리할 수 있는 방법을 고민했다.

통합되지 않을 수 있는 garbage data로 인한 비용 증가를 피하기 위해 클라이언트 저장소를 생각해 봤지만 저장 공간과 유지 기간에 대한 제약 사항이 있었다. RDB를 이용하는 경우도 로그인 성공 후 API를 직접 호출하는 것보다 Kafka를 이용한 통합이 확장성과 안정성 측면에서 이점이 있다고 생각했다.

시스템을 설계할 때는 여러가지 방향성을 모두 고려해서 주어진 환경에 적합한 설계를 하는 것이 중요하다고 생각한다. 이번 설계를 통해 단순한 기능 추가보다 ‘어떻게 잘 설계할 것인가’에 대한 고민을 하는 것이 중요하다고 느꼈다. 이번 설계를 통해 시스템의 확장성과 유지보수성을 함께 고민하는 시야를 키울 수 있었다고 생각한다.

This post is licensed under CC BY 4.0 by the author.

캐시 전략과 요구사항에 맞는 캐시 전략 선택하기

-