/Team4-BF2

우아한테크캠프 7기 4팀 최종 프로젝트 - 배달의민족 가게노출시스템

Primary LanguageJavaScript

🛵 BF2: Backend For Frontend

스크린샷 2024-08-29 오후 9 22 46

🎤 소개

우아한 테크캠프 7기 4팀 최종 프로젝트입니다.
배달의 민족의 많은 기능 중, 가게 노출 기능을 중점적으로 개발하였습니다.
가게 100만건, 메뉴 26000만건의 데이터를 EC2 small 3대, EC2 medium 3대로 평균 0.3초 이내의 응답율을 기록합니다.

✋팀원 소개

조희승 이지표 지찬우 홍은기

📒협업 전략

🌵브렌치 전략

  • 배포: main
  • 개발: dev
  • 기능 구현: feature/{issue_number}-{기능 이름}
  • 리팩토링: refactor/{issue_number}-{리팩토링 사항}
  • 버그 수정: fix/{issue_number}-{이슈 사항}
  • 설정: config/{issue_number}-{설정 사항}
  • 문서: docs/{issue_number}-{문서 내용}

🪢 Merge 룰

  • 삭제를 포함하여 200 ~ 300줄로 유지한다.
    • PR시 리뷰어들이 코드 리뷰에 들어가는 시간을 줄이고 최대한 많은 버그들을 미리 발견할 수 있도록 한다.

💬 코드 리뷰

  • PR 파트너가 PR을 올릴 시, 하던일을 중단하고 즉시 리뷰를 진행한다.
  • 코드 리뷰 멘트가 PR작성자에게 어떤 의미로 전달 되길 바라는지 알파벳으로 표현한다.
    • RCA룰을 준수한다.

📢 그라운드 룰

  • 어떤 방식으로든 이슈 발생 또는 진행 사항 등등 공유한다.
    • 예) 노션, 슬랙, 문서화 등...
  • 테크 스펙 작성하기
    • 기능을 개발하기 전 테크 스펙을 작성하고, 기능 개발을 완료했을 시 테크 스펙 링크를 같이 첨부하여 올린다.

🖊️ 기획

  • 현실적으로 3주안에 새로운 서비스 만드는 것은 어렵다고 판단되었습니다.
  • 사람들이 사용하지 않는 프로젝트를 만드는 것보다 기술에 초점을 맞추어 프로젝트를 진행하였습니다.
  • 배달의 민족의 다양한 기능 중 사용자들이 주문하기 위해 행하는 첫 동작인 가게 찾기 기능을 구현해보았습니다.
    자세히 보기...

📱 화면

BFF-검색화면 BFF-지역검색 BFF-무한스크롤 BFF-인기검색어 BFF-가게등록 BFF-메뉴등록

🛠️ 아키텍처

스크린샷 2024-08-29 오후 9 31 56

📝 프로젝트 기록들

📦 멀티 모듈 구조 채용

  • 같은 기능에 대해 사용하는 인프라를 바꾸는 일이 자주 발생될 것 같아 멀티 모듈 구조를 채용했습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 10 39

🔎 검색성능 최대 6000%(?) 개선!

  • MySQL에 Index를 추가하여 MySQL에서 속도 개선을 진행하였습니다.
  • MySQL의 Like 연산과 Elastic Search를 성능을 비교하였습니다.
  • Elastic Search를 사용할 경우 추가적인 리소스를 사용해야된다는 단점이 있었습니다.
  • 검색의 질, 검색의 속도를 고려하여 Elastic Search를 최종적으로 사용하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 31 56

✉️ 관심사의 분리: 이벤트

  • 가게, 메뉴, 리뷰 서비스에 이벤트를 도입하였습니다.
  • 각각 도메인에 데이터 변경사항이 발생하면, 이벤트를 발행하여 검색 서비스, 캐시 서비스에도 반영되도록 하였습니다.
  • Spring Application Event publisher를 사용하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 37 56

🔒 생각하지 못한 동시성 이슈: 락

  • 부하 테스트를 진행하는 중, 가게의 리뷰 수를 업데이트 할 때 생긴 리뷰 총 숫자와 리뷰 수의 값 불일치 현상이 발상하였습니다.
  • 여러가지 락을 공부해보고, 비관 락을 적용하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 40 41

🗂️ 데이터 베이스 부하를 줄이자: 캐시

  • Elastic Search에 검색 기준이 되는 최소 데이터만 보관, 검색에 결과로 id를 반환합니다.
  • id를 기준으로 MySQL에 가게 정보를 조회하였습니다.
  • MySQL의 부하를 줄이기 위해 캐시 서비스에서 자주 검색되는 가게 id에 대해 정보들을 보관하였습니다.
  • 캐시는 Redis로 작성되어 있습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 42 19

🔄 다양한 정보를 모아 보자: 비동기 요청

  • 검색 결과에 필요한 여러 정보들을 모아오는 상황을 배달의 민족과 유사하게 연출하였습니다.
  • 동기 요청과 비동기 요청에 대해 알아보았습니다.
  • 비동기 요청의 구현 방식중, RestTemplate을 비동기로 요청하는 방법과 WebClient 요청 방법의 성능을 비교해보았습니다.
  • 성능이 비슷하면서, 리소스를 적게 사용하는 WebClient 요청 방식을 사용하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 49 46 스크린샷 2024-08-30 오전 10 25 43 스크린샷 2024-08-29 오후 9 50 55

🛡️ 장애 전파를 막자: 서킷 브레이커

  • 서버 요청을 통해 데이터를 가져올 경우 외부 서비스에서 장애가 발생하면 호출한 서비스까지 영향을 받게 됩니다.
  • 장애 전파를 막기 위해 서킷 브레이커를 사용해보았습니다.
자세히 보기
스크린샷 2024-08-29 오후 9 53 31

📡 더 많은 데이터: 인프라 고민

  • 앱이 너무 잘되어서 입점 업체가 증가하면 어떻게 인프라 구조를 바꾸어야 할까요?
  • 더 효율적인 인프라로 비용도 줄이고, 성능도 높여보았습니다.
자세히 보기
스크린샷 2024-08-29 오후 10 27 57 스크린샷 2024-08-29 오후 10 28 25 스크린샷 2024-08-29 오후 10 28 46

🍃 리소스를 절약하자: WebFlux

  • 가게 노출 서버의 경우, 노출에 필요한 API 호출하여 정보를 취합하고 결과를 반환합니다.
  • 단순 비동기, blocking I/O를 사용하게 되면 수 많은 쓰레드를 사용하게 됩니다.
  • Netty를 사용하여 Event Loop기반으로 모든 요청과 응답을 받게 개선 하였습니다.
  • 기존 Spring MVC모델 대비 10%의 쓰레드를 사용하여도 더 높은 성능을 기록하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 10 10 58

👥 같이 잘 일하는 법: 팀 문화

  • 혼자 잘하기 금지!!
  • 매일마다 일일 퍼실리데이터를 정하여 스크럼을 진행하고, 커뮤니케이션 촉진을 담당하도록 하였습니다.
  • RCA룰을 사용하여 코멘트의 중요도가 명확하게 들어나게 하였습니다.
  • 프로젝트를 진행하면서 필요한 기술을 공부하고, 팀원에게 배운 내용을 설명하도록 하였습니다.
자세히 보기
스크린샷 2024-08-29 오후 10 13 34 스크린샷 2024-08-29 오후 10 13 54 스크린샷 2024-08-29 오후 10 21 36

🥲 못 해서 아쉬운 것 들

  • 엘라스틱 서치 bulk insert/update
  • 큐 서비스
  • 배달 가능 지역 고도화
  • 로드 밸런싱, 오토 스케일링