다중 pod를 이용한 쿠버네티스 환경에서 단체채팅방 구현 방법 - 채팅방 접속자 조회 기능 추가

dodo·2025년 1월 25일

GoogleDeveloperGroups

목록 보기
5/9
post-thumbnail

지난번 만들었던 채팅방에서 접속자 목록을 조회하는 기능을 추가하였다

최초 구현물

WebSocket을 이용해 사용자 연결 및 채팅방 입장, 실시간 메시지 수신, 사용자 목록 업데이트 등을 처리하는 로직을 구현했다.
사용자는 채팅방에 입장하기 전에 이름을 설정하고, 이를 WebSocket 서버에 전송해 사용자 정보를 등록한다.

이후 사용자는 채팅방의 메시지를 실시간으로 수신하고, 전역 사용자 목록을 실시간으로 갱신하여 화면에 반영할 수 있다.
채팅방에 입장할 때마다 입장 트리거가 작동해 여러 pod에서 구동 가능하도록 구현하였고, 채팅방에서 발생하는 메시지와 사용자 목록은 실시간으로 업데이트된다. 사용자가 채팅방을 떠날 때는 퇴장 트리거를 통해 접속 유저를 확인 가능하고, UI는 이를 자동으로 갱신하도록 임시로 구현했다.

또한, 여러 개의 Pod에서 동시에 WebSocket 서버가 동작할 수 있도록 로드 밸런싱을 고려하여 설계되어, 3개 이상의 Pod에서도 안정적으로 작동할 수 있다.

접속자 조회 흐름

1. 사용자 이름 설정 및 WebSocket 연결

사용자가 채팅방에 입장하기 전에, 반드시 사용자 이름을 설정해야 한다. 사용자가 이름을 설정하면 해당 이름을 WebSocket 서버에 전송하여 사용자를 등록한다. 이 과정은 채팅방에 처음 연결할 때 발생하며, 이름 설정 후 WebSocket 서버와 연결을 통해 해당 사용자를 채팅방에 추가할 수 있다.

2. 채팅방에 연결

사용자가 이름을 설정하고 나면, WebSocket을 통해 채팅방에 연결된다. 이때 채팅방의 이름이 제공되며, 사용자는 해당 채팅방에 입장하게 된다. 만약 사용자가 채팅방을 변경할 경우, 새로운 채팅방으로 WebSocket 연결을 다시 설정하여 입장한다.

3. WebSocket 연결 및 메시지 구독

WebSocket 연결이 성공하면 사용자는 해당 채팅방에서 발생하는 메시지를 실시간으로 받을 수 있도록 설정된다. 또한, 사용자는 전역 사용자 목록을 구독하여 실시간으로 채팅방에 속한 다른 사용자의 목록을 업데이트할 수 있다. 메시지가 채팅방에 도달하면, 이를 실시간으로 처리하여 화면에 표시한다.

4. 사용자 입장 알림

사용자가 채팅방에 입장할 때마다 rabbitMQ를 통해 서버로 queue를 전달하고 소비하여 전체 접속자 현황을 여러 pod에서 확인할 수 있다.

주요 흐름

WebSocket 연결: 클라이언트는 WebSocket 서버와 연결하여 채팅방에서 발생하는 메시지를 실시간으로 수신한다.
사용자 이름 설정: 사용자는 채팅방에 입장하기 전에 이름을 설정하고, 이를 서버에 전송하여 사용자를 등록한다.
메시지 및 사용자 목록 구독: 채팅방의 메시지와 전역 사용자 목록을 구독하여 실시간으로 갱신된 정보를 화면에 반영한다.
사용자 입장 알림: 사용자가 채팅방에 입장하면 이를 서버를 통해 저장한다.

하지만, pod 3개의 환경에서 간과한 부분이 있었다,, rabbitmq를 통해 입장과 퇴장은 각 pod마다 전송했으나 이를 저장하는 set이 인메모리형식이라 결국 도루묵,,

변경 핵심사항

가장 문제되는 부분인 Set을 인메모리 방식이 아닌 redis를 이용해 외부db로 관리하여 pod개수가 2개 이상이더라도 문제가 없도록 구현했다.
이 과정에서 기존에 사용하던 redis Serializer를 용도에 맞게 분할하였고 기존에 있던 기능들을 최대한 유지하면서 개선했다.

변경된 접속자 조회 흐름

1. 사용자 이름 설정 및 WebSocket 연결

사용자가 채팅방에 입장하기 전에, 반드시 사용자 이름을 설정해야 한다. 이 과정은 채팅방에 처음 연결할 때 발생하며, 이름 설정 후 WebSocket 서버와 연결을 통해 해당 사용자를 채팅방에 추가할 수 있다.

사용자 이름을 WebSocket으로 보낼 필요가 없다. why? 외부 브로커를 사용하기 때문에 모든 메시지에 유저 이름과 방 정보가 들어가기 때문!

2. 사용자 조회 로직 구독

1의 과정이 끝난 직후 바로 사용자 조회 엔드포인트를 구독하여 현재 접속중인 사용자를 바로 확인할 수 있게 한다. 단, 최초에는 채팅방에 입장하지 않았기 때문에 채팅방 이름은 "채팅방 미접속"으로 설정했다.

이로 인해 채팅방에 접속하기 전에도 현재 접속중인 사람을 확인할 수 있다.

3. UserStatusProducer를 사용하여 설정된 queue에 유저 정보 전송

이 과정에서 세션에 정보를 저장해두고, 이후에 사용한다. queue로 전송하는 과정에는 rabbitMQ가 사용된다.

4. UserStatusConsumer를 사용하여 queue 정보 획득

queue로 들어온 정보를 통해 현재 접속중인 유저를 저장하고, 이 과정에서 인메모리 -> Redis로 사용이 변경되었다.

실제 Redis에 저장이 잘 되는것을 확인할 수 있다.

5. 채팅방에 연결

사용자가 이름을 설정하고 나면, WebSocket을 통해 채팅방에 연결된다. 이때 채팅방의 이름이 제공되며, 사용자는 해당 채팅방에 입장하게 된다. 만약 사용자가 채팅방을 변경할 경우, 새로운 채팅방으로 WebSocket 연결을 다시 설정하여 입장한다.

이 과정에서 3~4의 과정이 계속 반복되어 전체 pod들이 모두 동일한 상태를 가질 수 있다

테스트유저가 테스트2 채팅방에 접속한 상황

6. WebSocket 연결 및 메시지 구독

WebSocket 연결이 성공하면 사용자는 해당 채팅방에서 발생하는 메시지를 실시간으로 받을 수 있도록 설정된다. 또한, 사용자는 전역 사용자 목록을 구독하여 실시간으로 채팅방에 속한 다른 사용자의 목록을 업데이트할 수 있다. 메시지가 채팅방에 도달하면, 이를 실시간으로 처리하여 화면에 표시한다.

7. 사용자 퇴장 알림

사용자가 채팅방에서 퇴장하면 UserStatusProducer의 EventListener가 웹소켓 연결해제를 감지하여 설정된 queue로 해당 유저의 퇴장 신호를 보내고, 4의 과정이 진행되어 Redis에서 유저 정보가 사라진다.

유저 퇴장 후 Redis (만약 다른 유저가 남아있다면 해당 유저의 정보들이 뜬다)

구현 화면

유저 A, 유저 B, 유저 C가 접속 후 채팅방 입장 전 (왼쪽부터 차례로 유저 A, B, C)

유저 A만 채팅방 "테스트1"에 접속

유저 B도 채팅방 "테스트1"에 접속

유저 C가 퇴장

profile
클라우드 데이터 플랫폼 주니어 개발자 도도입니다!

0개의 댓글