꿀벌 커뮤니티 내 채팅, 음성 서비스
Java : 11
SpringBoot : 2.6.3
JPA : 2.6.1
Redis : 6.2.6
Mysql : 5.7
Docker : 20.10.12
AWS EC2
OpenVidu
가장 앞단에 위치한 Nginx 는 Reverse Proxy 역할로, 소켓 및 HTTP 요청을 로드밸런싱 해준다.
proxy 서버로는 소켓 통신을 사용하는 chat-service 서버와 음성 채팅 세션을 관리하는 voice-service 서버를 두었다.
OpenVidu는 내장 NginX를 가지고 있다.
기존의 NginX의 포트와 OpenVidu의 포트에서 충돌이 발생했고, 기존 NginX의 포트를 81로 변경했다.
OpenVidu NginX를 custom했고, Main NginX의 설정과 하나의 파일로 관리했다.
-
HTTP Request 를 올바른 서비스로 매핑한다.
-
web-socket 통신을 위해 http header를 upgrade 한다.
Auth-Service는 외부에서 직접 접근할 수없고, chat, voice service에서 request를 보내 사용자가 인증되었는지 응답한다.
Auth-Service는 초기에 각 서비스에 모놀리식으로 포함되어 있었다. 하지만, 서비스가 추가되거나 jwt token claim이 변경될 수있다.
모놀리식으로 구축하면 모든 서비스의 인증 로직을 변경해야 한다. 이러한 이유로 인증 서비스를 분리하게 되었다.
인증 서비스는 가장 많은 트래픽을 받는다. 모든 서비스가 사용자 인증을 수행하기 때문이다.
사용자 인증이 필요할때 마다 외부 DB에 접근하는 것은 사용자가 서비스의 지연을 느끼게 만든다.
또한 실시간성이 중요한 채팅에서도 매번 사용자를 인증하기 때문에 reqeust 처리 시간을 줄일 필요성을 느꼈다.
redis를 캐시로 사용하는 방법을 사용했다. 최근에 해당 사용자가 인증을 받았는데 또 인증받기 위해 DB에 접근하는 시간을 줄이기 위해서다.
Auth-Service는 사용자 인증 요청이 들어오면 가장 먼저 redis 캐시를 확인한다. 만약 캐시에 유저 정보가 없으면 DB에 접근하고 response를 보낸다.
-
사용자 인증 서비스를 독립적으로 분리했다.
-
request를 처리하는 시간을 줄이기 위해 redis를 캐시로 활용했다.
소켓 통신을 위한 서브 프로토콜로 STOMP를 사용했다.
STOMP를 이용한 메시지 전달은 redis Publish/Subscribe 기능을 활용했고, 채널별로 message를 구별하기위해 redis에서 ChannelTopic을 관리했다.
채널은 수명을 가지고 있다. 수명은 사용자의 point를 활용해 증가시킬 수있다.
수명이 다하면 자동으로 채널이 닫힌다. 이를 구현하기 위해 redis의 TTL을 custom 했다.
모든 사용자는 채팅 로그를 요청할 수있다.
한번에 모든 채팅 로그를 불러오는 것은 비효율적이다.
무한 스크롤을 구현하여 사용자가 request를 보내면 특정 개수만큼 채팅 로그를 전송했다.
-
redis 자료구조를 이해하고 pub/sub system과 STOMP를 사용했다.
-
redis의 TTL을 custom 했다.
-
무한 스크롤을 구현해 채팅 로그를 N개씩 보내도록 구현했다.
OpenVidu 서버와 통신을 담당하는 서비스이다.
OpenVidu에 세션을 생성하고 세션별 사용자의 토큰을 발급받는다.
세션에 이미 참여한 사용자를 저장하기 위해 세션 저장소로 redis를 활용했다.
redis를 사용한 이유는 token 발급 서버가 여러대 증설되었을때, 데이터 일광성을 유지하기 위해 외부 저장소를 사용하기로 결정했다.
-
redis를 외부 session 저장소로 사용했다.
-
OpenVidu 라이브러리를 뜯어보고 사용했다.