[HBase 실습] Coupang

Hyunjun Kim·2025년 9월 2일
0

Data_Engineering

목록 보기
152/153

3 Coupang

쿠팡과 같은 쇼핑몰의 주 데이터 저장소를 HBase 로 한다고 했을 때, 어떤 데이터 모델과 key 설계를 해야할지 고민해보자.

쿠팡의 댓글 기능을 설계해본다.

3.1 요구사항

댓글기능을 중심으로 요구사항을 작성해 보았다.

  1. User 는 무한히 많아질 수 있다.
  2. Product 는 무한히 많아질 수 있다.
  3. Comment 는 Product 별로 남긴다.
  4. User 는 자신이 남긴 Comment 의 리스트를 시간순으로 볼 수 있다.
  5. Product 의 Comment 는 무한히 많아질 수 있다.
  6. Product 의 Comment 는 최신순으로 조회된다.
  7. Product 의 좋은 Comment 는 주기적(batch)로 계산해서 선정한다. Product 당 10만 남는다.


3.2 Class-D

Order : 주문을 해야 프로덕트의 코멘트가 남으니까 주문정보가 있어야 함.

  • order에 product 여러 개있을 순 있는데, 굳이 product와 연결하진 않았음. 댓글 시스템 할 거니까
    Product : content 는 이미지도 올라갈 수 있고 여러 가지 올라갈 수 있으니까 byteArray로 해놓았음. 그리고 생성된시간, 업데이트 된 시간 기록할 수 있도록 해놓았음
    Comment : 코멘트 자체에는 id를 두지 않았음. product id와 order id를 조합하면 유니크한 키가 됨. 요즘은 수정됨. 이라고 뜨니까 isEdited 등
class Comment {
    String orderld;
    String productid;
    String userld;
    String content;
    long timestamp;
    boolean isEdited;
}

class Order {
    String id;
    String userId;
}

class User {
    String id;
    String name;
    String nickname;
}

class Product {
    String id;
    String sellerId;
    byte[] content;
    long createdAt;
    long updatedAt;
}

class Seller {
    String id;
    String name;
}

Comment --> Order : dependent
Order --> User : dependent
Comment --> User : dependent
Comment --> Product : dependent
Product --> Seller : dependent


3.3 Table + Row Key

user

  • RowKey: id
  • Value: object 를 serialize

seller

  • RowKey: id
  • Value: object 를 serialize

product

  • RowKey: id
  • Value: object 를 serialize

order

  • RowKey: id
  • Value: object 를 serialize

comment

  • RowKey: orderId:productId
    • orderId: 10bytes
    • productId: 10bytes
  • Value: object 를 serialize

user-comment

  • 용도: index table
  • RowKey: userId:reverseTimestampOfComment
    • userId: 10bytes
    • reverseTimestampOfComment: 8bytes
  • Value: RowKey of comment
    • comment를 통째로 넣는 게 아니라 이것의 rowkey만 value로 넣을 것.

10개 조회해서 10개의 코멘트 row key얻은 다음에 그 rowkey로 코멘트들을 다시 조회하는 식이 될 것


product-comment

  • 용도: index table
  • RowKey: productId:c:reverseTimestampOfComment:reverseLengthOfContentInComment
    • userId: 10bytes
    • c: rank 와 comment 구분하기 위한 구분자
    • reverseTimestampOfComment: 8bytes
    • reverseLengthOfContentInComment: 4bytes
      • timestamp 가 중복되는 comment 들 사이의 구분과 정렬을 위해 사용
  • Value: RowKey of comment

RowKey에 가장 먼저 productId가 들어 가야 pid별로 모이고, 전체가 spot하게 분산이 될 것임. 잘 팔리는 상품은 리뷰를 동시에 여러 사람이 남길 수도 있으니 timestamp가 같은 서로 다른 리뷰들이 있을 수 있음. reverseLengthOfContentInComment를 콘텐츠 length를 길게 한 애들이 같은 시간에서는 더 앞에 올 수 있도록 위치시킴.


product-comment-rank

  • 용도: index table
  • RowKey: productId:r:number
    • userId: 10bytes
    • r: rank 와 comment 구분하기 위한 구분자
    • number: 2bytes (short)
      • 1-10 까지의 숫자 값으로 10개만 유지. upsert 식으로 사용.
      • short로만 해도 6536개가 65000개 넘게 표현이 되니까 2byte짜리 number를 하고
  • Value: RowKey of comment

결국 프로덕트에 남겨진 코멘트들 중에 좋은 코멘트들 10개씩 남긴다고 했으니 index table용도로 남기고, 이거를 어떤 걸 위치시킬지 계산하는 건 다른 시스템을 만들 거고, Overwrite 한다고 생각을 했다. 그래서 pid가 앞에 옴.
product-comment 와 RowKey의 길이 수가 다르다.

Value: RowKey of comment로 한 이유
우리는 Index table 방식을 채택했다. 코멘트 데이터는 양이 매우 많기 때문에, 이를 value로 직접 저장하면 스토리지를 많이 차지하는 단점이 있다. 또한 같은 데이터를 여러 곳에 저장할 경우 RDB처럼 트랜잭션으로 연결할 수 없으므로, 원본이 변경될 때마다 모든 저장소를 갱신해야 한다. 하지만 HBase는 이러한 다중 업데이트를 보장하기 어렵고, 이를 직접 구현하려면 시스템 복잡도가 높아져 버그 발생 가능성이 크다.
따라서 우리는 comment의 RowKey만 index table에 저장하기로 했다. RowKey는 일반적으로 변하지 않으므로, index table은 한 번 저장된 후 immutable하게 유지된다.

물론 이 방식은 index table 조회 후 원본 코멘트를 다시 조회해야 하므로 응답 속도가 다소 느려진다. 그러나 채팅 서비스처럼 밀리초 단위의 빠른 응답이 요구되는 것이 아니라, 쇼핑몰 코멘트 조회처럼 100~200ms 정도의 지연이 허용 가능한 서비스라면 충분히 감수할 수 있다고 판단했다. 결국, 속도보다 데이터 일관성과 관리 용이성을 우선시하여 이런 설계를 적용했다.



3.4 구현

이번 Coupang 시나리오의 구현은 위 KakaoTalk 을 참고해서 직접 구현해보자.
가능하다면 API 까지 디자인 해보면 좋다.

profile
Data Analytics Engineer 가 되

0개의 댓글