Skip to content

[Meet up with Mentor] 22.11.09

leegwae edited this page Nov 10, 2022 · 1 revision

[WEEK1] 22.11.09

이때까지 한 일

  • 그라운드 룰 작성
  • 백로그 작성
  • 기술 스택 결정

앞으로 할 일

  • DB 모델링 완성
  • 아키텍처 설계
  • API 정의
  • 디자인 프로토타입

MongoDB 관련

  • MySQL과 MongoDB 둘 중 MongoDB를 주 DB로 사용하려고 합니다.
    • 이유
      • MongoDB를 사용하는 것이 Async + Non-blocking 방식으로 Async인 Node와 같이 쓰기 좋다.
      • 온라인 채팅에서 엄청나게 많은 데이터가 쏟아져 나오는데, 이를 모두 관계형 데이터베이스로 처리하면 비효율적일 것 같다. (엄청난 조인)
    • 고민거리 : RDBMS가 설계하기 더 편하다. RDBMS를 사용할 수 있는 직관적인 ORM이 더 많다.
    • 사용자(N) : 채팅방(M)의 관계에서
      • RDBMS를 사용하면 N*M이 소요.
      • Document DB에 사용자 document에 자신이 속한 채팅방을 배열로 저장한다면 N*1 의 시간으로 단축이 될 것 같다?! → 이걸 장점으로 가져가도될까요?
  • NoSQL에서 전에 data가 100개 이상이면 document 분리를 하는 것이 좋다고 말씀해주신 것 같은데, 좀 더 정확하게 들을 수 있을까요?
    • rdb로 치면 컬럼이 100개 이상일 때 분리하는게 좋다는 의미인지??

ERD

모노 레포

  • 공통적으로 쓰이는 라이브러리는 아래 네개 정도인데, 모노레포 툴(Yarn workspace, Lerna …)을 사용해야 할까요??

    • 타입스크립트
    • Eslint
    • Prettier
    • Jest
  • 보통 모노레포라고 하면 위와 같은 툴을 사용하는걸 모노레포라고 하는지, 아니면 공통으로 사용하는 코드블럭만 상위 디렉토리로 빼는 것도 모노레포라고 하나요??

    생각하고 있는 프로젝트 구조

    .
      shared/
        types/
      client/
        react-project/
      server/
    		nest-project1/    (api)
        nest-project2/    (socket)
     eslint
     prettier
     package.json
    

배포 관련 (멀티 서버 배포)

배포할 때, react 빌드 파일을 제공하는 서버와 API, Socket 전용 서버를 나누려고 하는데, 어떻게 생각하시는지? (더 나은 방법이 있는지 궁금합니다.)

  • 프론트 서버와 백엔드 서버를 따로 배포하는 경우가 일반적인지?? (요즘에는 따로 서버를 배포하는 경우도 많다고 해서)

  • 프론트 서버를 따로 분리하는경우, Object Storage에 배포하는지, 이 경우 프론트엔드 서버에서 이미지도 함께 저장하는지.

  • React Build file → 정적 웹페이지

    Nginx) 정적 웹 페이지 서버, 프록시 서버, 캐시 서버 구축해보기

서버를 나누는 이유 : Socket 서버가 죽더라도 다른 기능은 할 수 있어야 안정적으로 동작할걸로 생각됨

[Nginx] 멀티 도메인 지원하기

socket 서버를 두 개 이상 둬야할까?

  • 서버 2개 사용시, 서버간에 데이터를 서로 공유해야 하는데(Redis 같은 것을 이용) 6주라는 기간이 짧아서 굳이 그렇게 할 필요가 있는지 고민입니다. 기술 난이도에 대한 조언을 얻고 싶습니다.
  • 서버 2개 사용 이유 : 서버의 부하를 줄이기 위해

밋업 기록

  • MongoDB를 써야하는 이유

    • 우리가 기획 중인 채팅 서비스에서는 MongoDB를 쓰는 것이 성능 측면에서 가장 좋아보인다.
    • 단, 클라이언트에서 데이터를 조합해 써야한다.
  • MySQL

    • Master, Slave 구조를 가지고 있다.

    • DB를 수정해야하는 경우(INSERT, UPDATE, DELETE, SELECT)는 마스터가, 일반적인 조회(READ)는 slave DB를 확인하는 구조이다.
      • 채팅을 치면 마스터에 추가된다. 그 후에 slave에 기록.
    • 복제 지연: 마스터의 write가 slave에 늦게 write되는 문제
      • 채팅을 친 후 바로 채팅을 가져오면 못 가져오는 문제가 있다. 이게 규모가 큰 MySQL에서는 심하다.
      • MongoDB는 도큐먼트에 직접 접근해서 복제 지연이 없다. 구조와 성능이 훨씬 좋을 것임. 정합성이 중요한 데이터가 별로 없어서 구조 좋은 거 같다.
  • Document DB에서 Data 100개 넘어가면 분리를 해야된다…에 대한 해석

    • 예를 들어 채팅이 100개가 넘어갈 수 있다. 그러면 Channel 도큐먼트 내의 채팅 배열에 채팅 도큐먼트를 쌓는 게 쉽고 편하다.
      • 그렇지만 채팅 도큐먼트의 크기는 크기 않으니, 채팅 객체를 100개씩 쌓고 이걸 메시지 도큐먼트로. 그리고 이 메시지 도큐먼트를 Channel 도큐먼트에 배열로 착착 넣기
      • 카톡도 오래된 메시지 불러오는데 오래걸리고 부분적으로 받아오니 유사하게 동작할 것이라 생각.
      • 최신 100개만 유지하고 그 이상은 백업하기
  • public 채널과 private 채널 구분 위해 Community 컬렉션에 따로 따로 배열을 저장해줘야할까?

    • 멘토님 의견
      • 따로 구분해좋을 것도 나쁜 방법은 아니다.
      • frontend에 RESTFul API 줄 때 private 채널에 속해있는지 알아야하는데, 만약 배열에 public, private 구분 없이 들어가있으면 클라이언트에서 다 받아서 걸려줘야함. 성능 부하를 덜 수 있음.
      • 근데 설계 자체는 channels 하나로 두는것이 깔끔하고 정규화를 지키기 때문에 좋아보인다.
      • 보통은 channels 하나 두고 성능 문제가 생기면 public이랑 private으로 쪼갠다.

    <aside> 💡 채널 모두 한 개의 배열에 넣어주는 게 좋아보인다. 이유 : 커뮤니티에 속한 채널들을 가지고 있는 것들이 좋을 것이다.

    </aside>

  • 모노레포…

    • yarn workspace 같은 툴을 써야 모노레포인가요? ㄴㄴ 툴 안 써도 모노 레포라고 한다. yarn workspace 제일 많이 쓴다. ㄱㄱ
  • 프론트랑 백엔드 따로 배포하는 거

    • 프론트 성능 많이 생기는 경우는 SSR이다. 근데 CSR이면 부하 별로 없음. 보통 SSR에서 프론트 서버는 몇십개씩 두는 경우가 많고 백엔드는 그보단 적게 둔다.
    • 근데 CSR이면 하나의 서버로 백엔드 동작하고 프론트 서빙하는 거 괜찮을 거 같음.
    • 우리가 보통 쓰는 서비스들은 SSR을 지원하고 트래픽 많아지면 자동으로 서버 켜서 트래픽 커버한다. 프론트 10개 늘어나면 백엔드는 2개 늘어남. 필요한 개수 차이가 많이 나기 때문에 따로 서빙하는 거임 우리는 CSR이니까 그럴 필요 없을듯
    • 채팅 이미지는 정적으로 넣고 프로필 이미지는 바뀔 수 있으니 별도의 스토리지에 저장할듯
      • 스토리지 뭐 쓸 거임? ncloud 안 쓰면 amazon s3 쓸 듯? 대부분은 amazon 쓴다. 클라우드 서비스 쓴다.
  • api랑 소켓 서버 분리

    • api 죽으면 소켓 살아있는게 좋을듯
    • 그리고 스케일 아웃 관점에서도 좋을듯 서버 개수 조절할 수 있으니까. 근데 그 전에 DB 부하올듯. 이런 경우에는 DB도 다중화해야함.
    • 보통 api보다 소켓 부하 심함
  • 설계는 사실 양날의 검임 동접자 수에 따라 설계가 완전 달라지기 때문에

    • 하지만 우리 구조 상에는 적절해보임
  • 소켓 서버 여러 개 어떤가요 우리가 개발이 4주라서 이거 가능할까요 백로그 다 하기도 힘들 거 같고 기술 난이도에 대한 조언을 얻고 싶다…

  • 사실 소켓만이 정답이 아님. API 계속 열어놓고 응답오면 그때그때마다 stream으로 보내는 방법도 있고 아니면 클라이언트에서 폴링(주기적으로 찌르기)할 수 있음. 근데 소켓이 제일 어려워보임. 그리고 하나의 서버에서 작동하는 소켓만 구현해도 큰 공부로 보임.

    • 서버 분산하는 방법 중에서 가장 간단한 거: 서버 3개 있으면 channel id를 별로 어떤 서버에 가야하는지 알 수 있음.. 이정도만 해도 다중화 괜찮음. 서버 분산하고 싶으면 추천
    • 지금 이 이미지의 구조는 부하를 분산시키는 구조가 아닌 듯. 메시지가 초당 백만개 왔다갔다하면 서버 A, B 동시에 부하가 가고 있는거임. 이 구조는 채팅에 효율적인 구조가 아닌 거 같음. 그리고 redis가 붙어야하는지 모르겠음. 실시간으로 할 때는 소켓 서버 A가 해주고(write) 이후에 입장한 사람은 API로 채팅 다 보내주면 될 거 같다. 다른 소켓 서버 B가 채널에 쏴주고? 뭔 소린지 몰랐음.
  • redis 쓸 거면 이 유투브 영상 참고해보세요 좋습니다.

  • env 분리 해보셨나요? cross env 써서 환경별(local,dev,stg,real)로 세팅해보세요

  • 음성 메시지 남기는 거 정도는 쉽게 구현할 수 있을듯?

  • OAuth 세 개 다 지원하는 거 어려울 거 같은데 하나만 하는게 어떤가요 그리고 카카오톡이 채팅 서비스인데 그걸로 하는 게 이상할듯

  • 인증/인가

    • 유저 정보 줄 때 리프레쉬 토큰 안 달려가게 하면 될듯? 비밀번호 안 달려가게 하는 것처럼
    • XSS 공격으로 cookie 탈환될 수 있으니까 httpOnly 설정
    • domain, path도 fix하면 좋을듯
    • secure 옵션은 local 개발할 때는 끄고 배포할 때만 키면 될듯
  • JWT는 stateless인데 리프레쉬 토큰 때문에 DB 접근하는 게 맞나?

    • 대부분은 session 많이 쓰긴 함. 애초에 DB에 저장해줄 거면 DB 접근해야하니까.
    • Redis 앞에 붙일 거면 DB 접근 나쁘지 않음
  • Cookie 옵션 중에서 Same-Site 옵션 공부해봐라

  • redux를 많이 쓰는 이유를 아시나요?

    • react + redux-thunk 쓰면 zustand랑 똑같을듯?
    • SSR이랑 연관도 있음. SSR에서 화면 그릴려면 API 요청해서 redux 상태 채워야하는데 그 채워진 상태를 브라우저에 위임해서 똑같이 사용할 수 있음. 이게 간편해서 redux 쓰는듯?
    • 제 생각엔 zustand 쓰면서 장점 단점 정리하고 썰 푸시면 좋을듯
  • 테스트는 대개 jest에 testing library 올려서 사용함

    • 행동 기반 테스트: 조금더 사용자 친화적인? 잘 모르겠음. react testing library 나오기전에는 클래스이름.버튼 ? 처럼 써줬어야했음. testing library 좋은듯
  • tailwind 러닝커브있는데 괜찮음?

    • 외워야할 거 있으니까
    • 반응형 지원 안할 거 같아서…
    • 이 서비스는 반응형 지원 힘들 거 같으니 그냥 web만 지원하게….
    • 아니면 채팅 서비스니까 모바일 맞춰서 하고 시간 남으면 반응형 부으면 될듯?

변경 사항 및 fix된 것 정리

피드백으로 변경된 사항 및 반영할 사항들을 정리합니다.

기존 변경 사항 혹은 반영할 사항 변경 이유 갱신 문서 링크
OAuth 로그인 전략으로 구글, 카카오톡, GitHub 지원하기로 하였음. GitHub OAuth만 제공하도록 한다. - 너무 많다. 백로그
모노레포 툴 쓰지않고 프로젝트를 구성하기로 하였음. 모노레포 툴(Yarn Workspace)을 쓰자. - 모노레포 툴을 쓰지 않고 구성이 가능하지 않을 것 같아서.
프론트 서버와 백엔드 서버를 따로 구축할지 고민 프론트 서버를 따로 구축하여 배포해보자 - 경험해보고 싶어서
이미지는 어떻게 저장할 것인지 고민 채팅 메시지의 이미지는 정적 파일로 저장, 프로필 이미지는 클라우드 서비스에 업로드하고 그 url을 DB에 저장 - 프로필 이미지는 자주 바뀌기 때문임.
사용할 Database 종류(MySQL 사용할지 MongoDB 사용할지 고민) MongoDB로 확정. - 보여드린 Document DB 설계에 대해서 긍정적인 피드백을 주셨다.
Document 분리 기준 채팅 message는 한 document에 100개 단위로 저장한다.
community document 내에서 private channel, public channel 분리 하나로 합쳐서 관리한다. - 정규화지키고… - 어차피 private인지 public인지 클라에서 알아야한다.
.env는 dev, production 개발환경 별로 작성하기로 하였음. .env를 local, dev, stg, real 개발환경 별로 작성하기로 함. - 멘토님이 local, dev, stg, real 참고해보라고 하셨음
리프레쉬 토큰 담을 쿠키에 httpOnly, path, secure 지정해주기로 함. (개발할 때는 secure 옵션 off) - domain 옵션도 추가 - 멘토 님이 domain 옵션을 고려해보라고 하셨음
Socket서버 여러개 띄우고 Redis를 사용하여 서버간 통신 Socket서버 일단 한 개 띄우고 나중에 확장하는 식으로 채팅 마다 동일 서버로 가면 소켓 서버끼리 통신해야할 필요 X
API랑 Socket서버 분리 의견 변화 없음 하나의 서버로 관리시, Socket의 부하로 인해 API요청이 지연될 수 있음 (나누는게 맞다)
JWT 어디 저장할지 (mongoDB) Redis에 넣으면 좋긴한데, 일단 mongoDB에 넣고 성능이슈 생기면 Redis앞에 붙여보자 Redis 앞에 붙일 거면 DB 접근 나쁘지 않음
Clone this wiki locally