팀 아스미
J017 권나영
J098 백수만
J104 송민종
J157 이준영
Asnity
ⓒ NAVER Connect Foundation
1. 프로젝트 소개
2. FE, 무엇을 고민했는가
3. BE, 무엇을 고민했는가
2
ⓒ NAVER Connect Foundation
CHAPTER 1.
프로젝트 소개
Asnity가 어떤 서비스인지 소개할게요.
ⓒ NAVER Connect Foundation
4
Asmi + Community
커뮤니티 기반 실시간 채팅 웹 애플리케이션
ⓒ NAVER Connect Foundation
5
Public
채널
Public
채널
Private
채널
커뮤니티
Asnity의 서비스 구조
ⓒ NAVER Connect Foundation
6
Asnity의 기능
#실시간_서비스 #커뮤니티_기반 #안_읽은_채팅_알림
데모 영상
배포 사이트: http://asnity.site
ⓒ NAVER Connect Foundation
7
사용 기술 Stack
팀 notion
https://url.kr/c1gsqx
ⓒ NAVER Connect Foundation
8
Architecture
팀 notion
https://url.kr/c1gsqx
ⓒ NAVER Connect Foundation
CHAPTER 2.
FE, 무엇을 고민했는가?
ⓒ NAVER Connect Foundation
모달을 관리하는 상태 최소화하기
ⓒ NAVER Connect Foundation
모달을 관리하는 상태를 최소화하기
ⓒ NAVER Connect Foundation
모달을 관리하는 상태를 최소화하기
ⓒ NAVER Connect Foundation
모달을 관리하는 상태를 최소화하기
모달 컨텐츠를 렌더링하기 위해 필요한 데이터를
모달 상태가 관리할 필요가 있을까?
모달이 열리고 닫히는 것만 제어하자
ⓒ NAVER Connect Foundation
모달을 관리하는 상태를 최소화하기
최종적으로 추상화된 모달 상태
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
토큰 기반 인증
토큰은 전역 상태(Zustand)로 관리
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
인증이 필요한 API 요청마다 반복되는 Authorization 헤더 삽입 로직
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
Axios의 Interceptors
interceptors로 요청 가로채기
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
Axios의 Interceptors에서 사용할 수 있도록
Zustand의 VanilaStore API 사용
React 컴포넌트에서도 사용할 수 있도록
custom hook 정의
ⓒ NAVER Connect Foundation
공통된 인증 로직 분리하기
Zustand Store에서 액세스 토큰을 가져옴
Axios의 Interceptors로
액세스 토큰을 Authorization 헤더에 삽입
=> 인증이 필요한 요청은 Interceptors를 설정한
Axios 인스턴스를 사용한다.
ⓒ NAVER Connect Foundation
채팅 전송시 Optimistic UI 적용하기
ⓒ NAVER Connect Foundation
22
채팅 전송시 Optimistic UI 적용하기
채팅 전송 시 Optimistic UI를 적용하여
채팅 즉시 렌더링
Optimistic UI란?
서버 상태를 변경하는 요청을 보내고,
해당 응답이 도착하기 전에 UI를 업데이트하는 패턴을 의미한다.
ⓒ NAVER Connect Foundation
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
채팅 전송시 Optimistic UI 적용하기
Socket.IO의 Acknowledgements를 사용하여,
HTTP 요청과 비슷하게, 발행한 소켓 이벤트와 대응되는 응답을 핸들링할 수 있다.
ⓒ NAVER Connect Foundation
25
채팅 전송시 Optimistic UI 적용하기
클라이언트가 관리하는 Chat 객체와
채팅 전송 상태를 나타내는 written 프로퍼티
ⓒ NAVER Connect Foundation
채팅 전송시 Optimistic UI 적용하기
Pending�written === -1
Success
written === true
Error
written === false
ⓒ NAVER Connect Foundation
CHAPTER 3.
BE, 무엇을 고민했는가?
ⓒ NAVER Connect Foundation
MongoDB와 Redis를 사용한
응답 속도 향상
ⓒ NAVER Connect Foundation
29
사용자가 속한 모든 커뮤니티에서
현재 참여 중인 채널들을 찾아
커뮤니티 정보와 채널 정보를 전달해주세요!
DB
커뮤니티
사용자
채널
*
*
*
*
*
1
참여
참여
MongoDB의 Sub-document를 활용한 탐색 속도 향상
ⓒ NAVER Connect Foundation
30
N:M 관계에서 2가지 필요
사용자 A명, 커뮤니티 B개, 채널 C개)
정보를 가져오기 위해 JOIN 테이블 검색 필요 (AxB + AxC)
커뮤니티
사용자
채널
*
*
*
*
*
1
사용자_커뮤니티
사용자_채널
MongoDB의 Sub-document를 활용한 탐색 속도 향상
ⓒ NAVER Connect Foundation
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
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
안 읽은 채팅 구현을 위한 설계
ⓒ NAVER Connect Foundation
34
안 읽은 채팅 표시 기능
ⓒ NAVER Connect Foundation
35
안 읽은 채팅 표시 기능
ⓒ NAVER Connect Foundation
36
마지막 방문 시간
채팅 생성 시간
안 읽은 채팅 표시 구현을 위해..
채팅 생성 시간과 사용자가 채널을 마지막으로 방문한 시간 비교 알고리즘 구현
ⓒ NAVER Connect Foundation
사용자의 각 채널 별 마지막으로 읽은 시간 저장
사용자 document
{
_id: <ObjectId>,
communities : {
<communityId> : {
channels : {
<channelId> : lastRead
…..
}
…..
안 읽은 채팅 표시 구현을 위해..
Client
Server
채널 방문 시간 업데이트 API 요청
PATCH /api/channels/:channelId/lastRead
API 응답 (성공 메세지)
채널 입장
or
채널 퇴장
ⓒ NAVER Connect Foundation
하나의 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
DevOps 자동화 여정
ⓒ NAVER Connect Foundation
DevOps 자동화 여정
Reviewer가 PR Merge 시 Slack 알림
Github Actions를 사용한
Integration Test
Server Docker image 생성
Docker-compose로 container 배포
Server 에러 발생 시 Slack의 에러 내용 알림
ⓒ NAVER Connect Foundation
모든 것엔 다 이유가 있어야지 시리즈
어떤 기술을 왜 사용하게 되었는지를 정리합니다.
무엇을 고민했는가? 시리즈
설계와 구현 과정에서 떠오르는 생각과 고민들을 정리합니다.
저희가 어떤 고민을 했는지 더 알고 싶나요?
ⓒ NAVER Connect Foundation
End of Document.
Thank You.
ⓒ NAVER Connect Foundation