같은 과 학생들과 함께 프로젝트 팀을 구성하여 팀 프로젝트를 진행하게 되었다.
특정 문제를 해결하는 것보다 기술적 능력을 향상 및 다양한 기술을 경험이 목표이다.
세부 주제는 WebRTC기반 스터디 그룹 프로젝트이다.
주요 구현 목표
- 미디어 / 시그널링 서버를 통한 WebRTC 스터디
- WebSocket을 활용한 접속 상태
- On/Off 버튼을 통한 실시간 사용자 공부 시간 관리
- 실시간 데이터를 관리하기 위한 상태 관리 서버
- 그룹 채팅
아키텍처
미디어 & 시그널링
- Client끼리 WebRTC를 하기위해 시그널링 서버를 통해 SDP 및 ICE Candidate 정보 전달
- (COTURN을 통해 STUN 서버도 구축)
- 이렇게 받은 정보를 토대로 미디어 서버를 통해 WebRTC 통신
- Client 들의 방 입장과 퇴장은 실시간으로 웹소켓 설정을 통해 관리
순공 시간
- 타이머 측정 방법
- 순공 시간 ON 요청 시 시작 시간 기록
- 공부 시간을 요청하면 현재시간 - 시작시간 + 공부시간 을 보냄
- 현재시간 - 시작시간 => 현재 ON 되어 기록된 공부 시간
- 공부시간 -> 이전에 ON 했다가 OFF한 이전에 공부한 시간(오늘 중)
- 접속 해제되면 현재시간 - 시작시간을 공부시간에 저장하고 시작시간을 초기화함.
- 접속 해제 => 채팅 소켓 close OR WebRTC 연결 해제 OR OFF 버튼 클릭
- 사용 예
- B가 최초 방 접속 시, A 사용자 시작시간을 바탕으로 서버에서 응답
- B 사용자는 해당 A 사용자의 시작 시간을 바탕으로 프론트에서 1초씩 갱신하며 화면에 띄움
- 이유
- 주기적으로 요청을 보내는 방식 대신 시작 시간을 기반으로 활용하면 DB에 쓰기 횟수를 줄일 수 있음.
- 이는 사용자가 많으면 많을수록 DB 쓰기 시간을 더 효율적으로 줄일 수 있을 것이라고 생각됨.
- 프론트에서 1초씩 갱신하며 띄우는 이유는 사용자가 많을 수록 서버에서 각 사용자별 1초씩 계속 갱신하는 것은 비효율적
- "React 상태관리를 통해 사용자 체감상 어느 정도 실시간에 가까운 퀄리티로 구현할 수 있지 않을까" 라고 추측
- 주기적으로 요청을 보내는 방식 대신 시작 시간을 기반으로 활용하면 DB에 쓰기 횟수를 줄일 수 있음.
채팅
- 웹 소켓을 Kafka에 연결하고 채팅방 별로 Path Variable을 통해 구독해서 데이터를 받음
- 채팅은 MongoDB에 저장되며 3일 이상 지난 데이터들은 Batch로 일괄 제거
푸시
- 사용자 미접속 시 웹 푸시 알림 전송
접속 상태
- 상태 관리 서버를 통해 관리
- 접속 상태를 갱신하는 방법
- 사용자 접속 시 스터디방에 들어가지 않더라도 Default(전체) 스터디 방 소켓에 연결
- 사용자가 스터디방 들어가면 해당 스터디방 소켓에 연결
- 따라서 중복 입장을 막고 항상 소켓을 하나에만 연결하여 소켓 연결 여부(웹소켓 세션)를 통해 접속 상태 관리
- 이유
- 접속 상태를 위한 별개의 소켓을 연결하게 되면 스터디방 접속 시 소켓을 두개 연결해야한다.
- 10000명이 접속한다고 치면 10000개의 소켓 연결 대신 20000개의 소켓을 연결해야하는 셈
- 그러나, 제시한 방법의 경우에도 스터디방에 접속하지 않더라도 소켓이 Default 스터디방에 연결되어 있기 때문에 어느정도 리소스를 잡아먹을 것으로 추측.
상태관리
- 상태 관리 서버는 비교적 빠른 Redis에 실시간 데이터를 저장
- 여러 서버에서 동시에 Redis로 접근하거나, MSA 설계를 고려하여 상태관리를 위한 서버를 따로 구현
- 실시간 성을 위해 TCP 통신을 활용
게이트웨이
- 토큰 검증
- 라우팅
인증 + 유저
- 토큰 발급/재발급
- 로그인/로그아웃
- 자동 로그인
- 기타 유저 관련 동작 수행
디렉토리 구조
디렉토리 구조를 지정하여 개발하기로 하였다.
controller,service,repository(+entity), dto, model, exception을 기본으로 사용하고 필요 시 추가하여 사용한다.
├── project
│ ├── servername
│ │ ├── controller
│ │ │ └── MemberController.java
│ │ ├── service
│ │ │ ├── MemberProfileService.java
│ │ │ ├── MemberSearchService.java
│ │ │ ├── MemberSignUpRestService.java
│ │ │ └── MemberSignUpService.java
│ │ ├── repository
│ │ │ ├── entity
│ │ │ │ └── MemberFindEntity.java
│ │ │ ├── MemberPredicateExecutor.java
│ │ │ ├── MemberRepository.java
│ │ │ ├── MemberSupportRepository.java
│ │ │ └── MemberSupportRepositoryImpl.java
│ │ ├── dto
│ │ │ ├── MemberExistenceType.java
│ │ │ ├── MemberProfileUpdate.java
│ │ │ ├── request
│ │ │ │ └── SignUpRequest.java
│ │ │ └── response
│ │ │ │ └── MemberResponse.java
│ │ └── model
│ │ │ ├── Address.java
│ │ │ ├── Email.java
│ │ │ └── Name.java
│ │ └── exception OR error
│ │ ├── EmailDuplicateException.java
│ │ ├── EmailNotFoundException.java
│ │ └── MemberNotFoundException.java
│ │ ├ . . . (서버마다 추가로 필요한 파일들)
추가 활용
dto - 주로 req,res 혹은 변환용
config - 설정
model - POJO
security - 보안
util - 기타 기능 지원
validation - 유효성 검증
요청 / 응답
요청 응답의 형식을 통일 하였으며 그 예시는 아래와 같다.
오류 코드는 {서버}-{번호} 형식으로 하고 enum으로 관리한다.
Request
roomId : long
page : int (시작 : 1)
size : int (시작 : 1)
Response
{
"result": "SUCCESS",
"message": "get chats in room with paging successfully",
"data": [
{
"_id": "642a72138760af600cabb376",
"roomId": "test",
"senderId": "test-user1",
"messageType": "TEXT",
"content": "테스트 메시지 입니다.",
"createdAt": "2023-04-03T15:28:35.467"
},
...
]
}
ErrorResponse
{
"result": "Failed",
"message": "해당 방에 존재하는 채팅이 없음.",
"data": {
"errorCode": "CHAT-001",
"timestamp": "2023-04-02T23:42:24.464286",
"message": "채팅이 존재하지 않는 경우"
}
}
Git
깃 브랜치는 Main - release - develop - feature형식을 사용하며
이슈는 템플릿을 만들어 아래와 같이 사용한다.
'프로젝트 > WebRTC - studyhub' 카테고리의 다른 글
[WebRTC] 마이크로서비스 간 gRPC 통신 - 개발편(2) (0) | 2023.11.09 |
---|---|
[WebRTC] 단위 테스트/통합 테스트 (0) | 2023.11.07 |
[WebRTC] 채팅 서버 - 채팅 메시지 순서 보장(카프카 순서 보장) (2) | 2023.11.03 |
[WebRTC] 마이크로서비스 간 gRPC 통신 - 개발편(1) (0) | 2023.08.16 |