1 of 42

팀 아스미

J017 권나영

J098 백수만

J104 송민종

J157 이준영

Asnity

ⓒ NAVER Connect Foundation

2 of 42

1. 프로젝트 소개

  • Asnity의 서비스 구조
  • Asnity의 기능
  • 사용한 기술 stack
  • Architecture

2. FE, 무엇을 고민했는가

  • 모달을 관리하는 상태 최소화하기
  • 공통된 인증 로직 분리하기
  • 채팅 전송시 Optimistic UI 적용하기

3. BE, 무엇을 고민했는가

  • MongoDB와 Redis를 사용한 응답 속도 향상
  • 안 읽은 채팅 구현을 위한 설계
  • DevOps 자동화 여정

2

ⓒ NAVER Connect Foundation

3 of 42

CHAPTER 1.

프로젝트 소개

Asnity가 어떤 서비스인지 소개할게요.

  • Asnity의 서비스 구조
  • Asnity의 기능
  • 사용한 기술 stack
  • Architecture

ⓒ NAVER Connect Foundation

4 of 42

4

Asmi + Community

커뮤니티 기반 실시간 채팅 웹 애플리케이션

ⓒ NAVER Connect Foundation

5 of 42

5

Public

채널

Public

채널

Private

채널

커뮤니티

Asnity의 서비스 구조

ⓒ NAVER Connect Foundation

6 of 42

6

Asnity의 기능

#실시간_서비스 #커뮤니티_기반 #안_읽은_채팅_알림

  • 팔로우 / 언팔로우 자신의 팔로잉, 팔로워 목록 관리
  • 채널 참여 커뮤니티에 참여하여 사용자들과 소통할 채널 개설
  • 접근 권한 Public / Private 채널 및 관리자/참여자 구분
  • 안 읽은 채팅 다른 채널에 새로운 채팅이 있는지 실시간으로 확인 가능

데모 영상

배포 사이트: http://asnity.site

ⓒ NAVER Connect Foundation

7 of 42

7

사용 기술 Stack

팀 notion

https://url.kr/c1gsqx

ⓒ NAVER Connect Foundation

8 of 42

8

Architecture

팀 notion

https://url.kr/c1gsqx

ⓒ NAVER Connect Foundation

9 of 42

CHAPTER 2.

FE, 무엇을 고민했는가?

  • 모달을 관리하는 상태 최소화하기
  • 공통된 인증 로직 분리하기
  • 채팅 전송시 Optimistic UI 적용하기

ⓒ NAVER Connect Foundation

10 of 42

모달을 관리하는 상태 최소화하기

ⓒ NAVER Connect Foundation

11 of 42

모달을 관리하는 상태를 최소화하기

ⓒ NAVER Connect Foundation

12 of 42

모달을 관리하는 상태를 최소화하기

ⓒ NAVER Connect Foundation

13 of 42

모달을 관리하는 상태를 최소화하기

모달 컨텐츠를 렌더링하기 위해 필요한 데이터를

모달 상태가 관리할 필요가 있을까?

모달이 열리고 닫히는 것만 제어하자

ⓒ NAVER Connect Foundation

14 of 42

모달을 관리하는 상태를 최소화하기

최종적으로 추상화된 모달 상태

ⓒ NAVER Connect Foundation

15 of 42

공통된 인증 로직 분리하기

ⓒ NAVER Connect Foundation

16 of 42

공통된 인증 로직 분리하기

토큰 기반 인증

토큰은 전역 상태(Zustand)로 관리

ⓒ NAVER Connect Foundation

17 of 42

공통된 인증 로직 분리하기

인증이 필요한 API 요청마다 반복되는 Authorization 헤더 삽입 로직

ⓒ NAVER Connect Foundation

18 of 42

공통된 인증 로직 분리하기

Axios의 Interceptors

interceptors로 요청 가로채기

ⓒ NAVER Connect Foundation

19 of 42

공통된 인증 로직 분리하기

Axios의 Interceptors에서 사용할 수 있도록

Zustand의 VanilaStore API 사용

React 컴포넌트에서도 사용할 수 있도록

custom hook 정의

ⓒ NAVER Connect Foundation

20 of 42

공통된 인증 로직 분리하기

Zustand Store에서 액세스 토큰을 가져옴

Axios의 Interceptors로

액세스 토큰을 Authorization 헤더에 삽입

=> 인증이 필요한 요청은 Interceptors를 설정한

Axios 인스턴스를 사용한다.

ⓒ NAVER Connect Foundation

21 of 42

채팅 전송시 Optimistic UI 적용하기

ⓒ NAVER Connect Foundation

22 of 42

22

채팅 전송시 Optimistic UI 적용하기

채팅 전송 시 Optimistic UI를 적용하여

채팅 즉시 렌더링

Optimistic UI란?

서버 상태를 변경하는 요청을 보내고,

해당 응답이 도착하기 전에 UI를 업데이트하는 패턴을 의미한다.

ⓒ NAVER Connect Foundation

23 of 42

23

채팅 전송시 Optimistic UI 적용하기

Client 1

커뮤니티 A

Socket Server

채널 1

Client 2

커뮤니티 A

채널 1

API Server

DB

Client → Socket 서버로 전송

Socket 서버 → API 서버로 전송

DB 쓰기 및 결과 반환

④ API 서버 → Socket 서버로 응답

Socket 서버 → Client로 응답.

ⓒ NAVER Connect Foundation

24 of 42

24

채팅 전송시 Optimistic UI 적용하기

Socket.IO의 Acknowledgements를 사용하여,

HTTP 요청과 비슷하게, 발행한 소켓 이벤트와 대응되는 응답을 핸들링할 수 있다.

ⓒ NAVER Connect Foundation

25 of 42

25

채팅 전송시 Optimistic UI 적용하기

클라이언트가 관리하는 Chat 객체와

채팅 전송 상태를 나타내는 written 프로퍼티

ⓒ NAVER Connect Foundation

26 of 42

채팅 전송시 Optimistic UI 적용하기

Pending�written === -1

Success

written === true

Error

written === false

ⓒ NAVER Connect Foundation

27 of 42

CHAPTER 3.

BE, 무엇을 고민했는가?

  • MongoDB와 Redis를 사용한 응답 속도 향상
  • 안 읽은 채팅 구현을 위한 설계
  • DevOps 자동화 여정

ⓒ NAVER Connect Foundation

28 of 42

MongoDB와 Redis를 사용한

응답 속도 향상

ⓒ NAVER Connect Foundation

29 of 42

29

사용자가 속한 모든 커뮤니티에서

현재 참여 중인 채널들을 찾아

커뮤니티 정보와 채널 정보를 전달해주세요!

DB

커뮤니티

사용자

채널

*

*

*

*

*

1

참여

참여

MongoDB의 Sub-document를 활용한 탐색 속도 향상

ⓒ NAVER Connect Foundation

30 of 42

30

N:M 관계에서 2가지 필요

  1. 사용자가 속한 커뮤니티를 찾는 연산
  2. 해당 커뮤니티에서 사용자가 속한 채널을 찾는 연산

사용자 A명, 커뮤니티 B개, 채널 C개)

정보를 가져오기 위해 JOIN 테이블 검색 필요 (AxB + AxC)

커뮤니티

사용자

채널

*

*

*

*

*

1

사용자_커뮤니티

사용자_채널

MongoDB의 Sub-document를 활용한 탐색 속도 향상

ⓒ NAVER Connect Foundation

31 of 42

31

사용자 document

MongoDB의 Sub-document를 활용한 탐색 속도 향상

{

_id: <ObjectId>,

communities : {

<communityId> : {

channels : {

<channeltId> : lastRead

…..

}

…..

커뮤니티 document

{

_id: <ObjectId>,

otherInfo…..

}

{

_id: <ObjectId>,

otherInfo…..

}

채널 document

사용자 document는 Sub-document로 자신이 속한

커뮤니티와 채널의unique id 값을 Sub-document로 저장

해당 id를 reference로

자신의 커뮤니티, 채널의 document에 바로 접근 가능

ⓒ NAVER Connect Foundation

32 of 42

32

Redis를 사용하여 재사용성이 높은 데이터 캐싱

Update 빈도는 낮지만 Read 요청이 잦은 Data인 사용자 기본 정보는

Redis를 활용하여 Caching

사용자 기본 정보 : unique ID, 사용자 ID, 닉네임, On/Offline 상태, 계정 생성일

DB

Cache

현재 사용자 정보

커뮤니티에 속한 사용자 정보

채널에 속한 사용자 정보

요청 Data

바로 DB에 접근

Cache에 먼저 접근

성능개선율

자신의 정보

13.1ms

4ms

230%

특정 채널의 사용자 정보

23.8ms

13.9ms

71%

커뮤니티 내 사용자 정보

14.7ms

12.1ms

18%

Client

Server

Cache Hit

Cache Miss

응답 20번 측정치의 medium

ⓒ NAVER Connect Foundation

33 of 42

안 읽은 채팅 구현을 위한 설계

ⓒ NAVER Connect Foundation

34 of 42

34

안 읽은 채팅 표시 기능

ⓒ NAVER Connect Foundation

35 of 42

35

안 읽은 채팅 표시 기능

ⓒ NAVER Connect Foundation

36 of 42

36

마지막 방문 시간

채팅 생성 시간

안 읽은 채팅 표시 구현을 위해..

채팅 생성 시간과 사용자가 채널을 마지막으로 방문한 시간 비교 알고리즘 구현

ⓒ NAVER Connect Foundation

37 of 42

사용자의 각 채널 별 마지막으로 읽은 시간 저장

사용자 document

{

_id: <ObjectId>,

communities : {

<communityId> : {

channels : {

<channelId> : lastRead

…..

}

…..

안 읽은 채팅 표시 구현을 위해..

Client

Server

채널 방문 시간 업데이트 API 요청

PATCH /api/channels/:channelId/lastRead

API 응답 (성공 메세지)

채널 입장

or

채널 퇴장

ⓒ NAVER Connect Foundation

38 of 42

하나의 ChatList는 100개의 채팅을 저장

ChatList의 처음 채팅 시간(firstChatTime)으로 안 읽은 채팅이 있는지 확인

ChatList의 Field Chats를 이진 탐색으로 안 읽은 채팅의 시작 index 탐색

_id

firstChatTime

Chats

99

ChatList document

안 읽은 채팅 표시 구현을 위해..

Client

Server

최신 채팅 내용을 가져오는 API 요청

GET /api/channels/:channelId/chat?prev=-1

안 읽은 채팅 위치 찾는 API 요청

GET /api/channels/:channelId/unread-chat

API 응답 (채팅 내용 전달)

API 응답 (안 읽은 채팅 위치)

채널 입장

채팅 렌더링

_id

firstChatTime

Chats

199

_id

firstChatTime

Chats

299

_id

Chats

360

firstChatTime

{

senderId: …

content: …

}

Chat

ⓒ NAVER Connect Foundation

39 of 42

DevOps 자동화 여정

ⓒ NAVER Connect Foundation

40 of 42

DevOps 자동화 여정

Reviewer가 PR Merge 시 Slack 알림

Github Actions를 사용한

Integration Test

Server Docker image 생성

Docker-compose로 container 배포

Server 에러 발생 시 Slack의 에러 내용 알림

ⓒ NAVER Connect Foundation

41 of 42

모든 것엔 다 이유가 있어야지 시리즈

어떤 기술을 왜 사용하게 되었는지를 정리합니다.

무엇을 고민했는가? 시리즈

설계와 구현 과정에서 떠오르는 생각과 고민들을 정리합니다.

저희가 어떤 고민을 했는지 더 알고 싶나요?

ⓒ NAVER Connect Foundation

42 of 42

End of Document.

Thank You.

ⓒ NAVER Connect Foundation