[Numble] E-commerce 마이크로 서비스 설계 딥다이브 회고록

JJ G_G·2023년 4월 30일
0

평소에 하고싶었던, 공부하고싶었던 (공부 하고있던) 도메인 (e-commerce, 성능 테스트, 동시성 이슈 등) 에 흥미가 생겨 바로 결제하게 되었다.

중급 난이도로 설정되어 있었고 한번 도전하고 싶었다.
도전하고 보니 나는 심각한 주니어 인 것 같다...

1. 서비스 설계하기

넘블샵은 창립 1주년을 맞아 100% 할인 쿠폰을 10,000장 발급하기로 결정했다. 이번 이벤트를 맞아 범용적인 쿠폰 시스템을 마이크로서비스로 개발하고자 한다. 쿠폰 시스템은 다음과 같은 요구 사항을 만족해야 한다.

  • 할인 쿠폰에 대한 범용적인 쿠폰 시스템의 마이크로서비스를 개발해야 한다.

  • 다음과 같이 ERD 를 설계하고 type을 통해 수량이 있는 쿠폰과 없는 쿠폰 을 구분했다.

  • 수량이 있는 type의 coupon의 경우 반드시 coupons_stock 테이블의 레코드가 존재한다.

아키텍처

  • 위와 같이 테이블을 만들다 보니 coupons_stock (수량) 을 read하는 기능(쿠폰 전체 보기, 유저에게 쿠폰 발급하기)이 두개가 존재했다.
  • 유저에게 쿠폰 발급하기 기능 때는 coupons_stock 테이블의 read가 굉장히 중요하다
  • 재고가 존재하는지, 동시 발급받은 유저는 존재하는지에 따라 결과가 달라지므로 '동시성 이슈' 가 있는 테이블이였다.
    • 유저가 발급받을 당시 재고 상황은 유저 입장에서 '꼭' 맞아야 하는 개수가 아니라고 생각했다.
  • 쿠폰 전체보기 에 대한 coupons_stock read 는 redis에 저장하고, 배치(5분)를 수행하여 해당 count 데이터를 sync 했다.

개발

  • 기술 스택
    • Typerscript, NestJs, jest, Prisma, Postgresql, redis, docker compose

2. 해결해야할 요구사항

개발 요구 사항

  • numble 가이드 notion 페이지에 비기능 명세서, 기능 명세서 등 실제 기획자와 협업하는 듯한 느낌을 받는 기획서가 존재했다.
  • 해당하는 기획서에 따라 설계, 및 개발을 진행하면 되었다.
  • API (하단의 github 참고)
    • 요구사항에 따라 API를 개발했다.
  • gRPC
    • gRPC로 개발 했을때 가산점이 있었다.
    • RestfulAPI로만 개발했고, gRPC로 변경한다고 그리 어려울 것 같지 않았다.
    • 하지만 gRPC는 그리 만만하지 않았다 ...
    • FindAll 의 경우 Response에 정의된 property에 맞게 값을 return 해줬어야 했는데 한참 헤메었다.

동시성 이슈 해결

성능 테스트

  • 성능 테스트는 k6로 진행했고 시각화는 grafana 로 진행하였다.

  • 쿠폰 발급에 대한 시나리오 테스트만 진행했다.

    • 발급 가능한 쿠폰 읽기 -> 쿠폰 발급하기.
  • vuser 를 150~200 사이일때 더이상 iterations 값이 오르지 않았다.

    • vuser 150~200 사이가 임계점이라고 생각했다.
    • 병목이 걸리는 지점을 찾아서 개선이 필요했었지만 개선하지 못햇다.
  • 성능 테스트에 대한 시나리오 작성에 대한 궁금증도 존재했다.

    • 모든 시나리오 (쿠폰발급, 쿠폰읽기, 쿠폰사용, 쿠폰사용취소) 를 동시에 실행해야 하는가 ? 하나의 기능들만 테스트 하는 것인가 ?
    • 'response 성공' 만 테스트 하는가 ?
    • '발급 실패' 일 경우에도 요청이 성공한 것이 아닌가 ?
    • 부하 테스트의 성공기준은 어떻게 설정하는가 ?
  • 다음 성능 테스트에 대한 시간이 있을 때 진행이 필요할 것 같다.

3. 후기

  • 개인적으로 정말 배운게 많았던 시간이였다.
  • 약 2주동안 (23/04/17 ~ 23/04/30) 진행되었지만 회사 이슈로 ... 22일부터 본격적으로 진행해서 30일까지 개인휴가를 내면서 진행했다.
  • 평소 고민이였던 동시성 이슈, read write의 분리 (재고 같은 경우 지속적인 read에 대한 해결법), 테스트 시나리오, 성능 테스트 등등 평소 겪어보지 못했던 이슈들, 그리고 요구사항등을 통해 시야가 넓어진 것 같다.
  • redis 를 활용한 read 분리
    • '재고' 의 경우 데이터를 사용자에게 실시간으로 보낼 필요 없는 도메인일 경우 ex) 좋아요 개수, 조회수 등등 해당 방식으로 처리한다 라고 듣기만 했었다.
    • 실제로 설계 및 개발은 처음 진행해 보았다.
  • 동시성 이슈
    • 동시성 이슈를 DB 단에서 회피하는 '비관적 락' 방식 밖에 몰랐고, 실제 동시성 이슈를 해당 방법으로 해결해왔다.
    • 이번 계기를 통해 낙관적 락에 대한 개발과 이슈 해결을 통해 배울 수 있었다.
  • 성능 테스트
    • k6 를 통한 성능 테스트를 진행할 수 있었다.
    • k6 실행 및 grafana 로 시각화 하는 방법 등을 통해 다시 하게된다면 수월하게 진행할 수 있을 것 같다.

아쉬웠던 점

  • 개발 관련

    • 평소 sequential 한 code 만 작성했었는데 최근 Nest JS 에 대한 관심으로 관심사 분리, 경계 설정하기 등의 연습을 하고 있었다.
    • 위와 같은 요소들을 고민하면서 시간을 많이 소모했다.
  • 하지만 성능 테스트, e2e 테스트, 및 도커 등 해당 부분은 시간이 많이 부족했고 해결하지 못한 부분도 많다.

    • 성능 테스트는 측정만 했지 이후 개선을 하지 못했다.
    • 실제로 병목이 걸리는 부분, 어떤 슬로우 쿼리가 발생했는지에 대한 로깅에 대한 관찰이 부족했다.
    • 실제로 성능 테스트는 scale out (기존 요구사항에 개발할 필요 없다고 했지만 실제 레포트에 대한 결과로 어떻게 개선되는지 해보고싶다.) 는 못해봤다.
  • 성능 테스트

    • 성능 테스트를 해야 한다 라고만 생각하고 실제로는 처음해보았다.
      • k6를 통해 성능 테스트를 진행했는데 gRPC 도 처음이다 보니 각각의 지표들이 무엇을 의미하는지, http와는 값들이 달라 알 수가 없었다.
      • 다음에 http, REST API로 변경해서 테스트를 다시 진행해봐야겠다.
  • 서버

    • 급한대로 안쓰던 노트북으로 성능테스트를 실시했다.
      • 도커, grafana k6 등 일단 돌려보고 cloud 에서 해보자 라고 했던게 시간이 부족해서 결국 노트북 성능테스트를 제출했다.
      • 성능 테스트에 대한 레포트를 작성했을 때 결국 metric, grafana 지표, 시나리오를 어떻게 짜야하는지 등 생각하느라 결국 후순위로 밀렸고, 결국 부족한 과제로 많이 남게되었다.
  • 도커

    • 도커를 처음 해보았다.
      • 명령어 실행, docker 설정, docker compose 실행 등 설치만 하는데도 너무 오랜 시간이 걸렸다.
      • 결국 nest server 를 띄우는데 까지는 성공했는데, 이후 호출 및 테스트 까지는 하지 못했다.

향후 계획

  • 성능 테스트 재 실시 cloude scale out 등
  • 성능 테스트 metric에 대한 조사, vues와 목표 RPS 설정 식 새롭게 찾기
  • gRPC 가 아닌 REST API로 변경 후 진행
    • '클린 아키텍처' 로 인한 의존성 변경에 대해 편리하게 개발되어있는지 확인 할 수 잇을 것 같다.
  • docker compose 설정 배포 환경 구성하기
  • CI 환경에서 e2e test 자동화
    • github action으로 e2e 테스트를 올려봤는데 3시간이 걸려도 완료되지 않았다. (...)
    • CI 환경에서 e2e test는 하지 않는지? 아니면 방법이 잘못된 것인지 확인이 필요하다.
  • 기존 copang 프로젝트에 coupon service를 어떻게 도입할 수 있을지 고민
profile
Node 벡엔드 개발자

0개의 댓글