안녕하세요. 저는 이번 프로젝트에서 WebSocket 기반의 실시간 그룹 채팅 시스템을 구현했습니다.
이 기능이 왜 필요했는지를 먼저 말씀드리면,
저희 서비스에는 그룹 기능이 존재했지만, 그 안에서 실시간 소통 수단이 전혀 없었습니다.
처음에는 REST API로 채팅 기능을 구현해봤지만,
실제로 써보니 응답 지연, 트래픽 과다, 사용자 경험 저하 문제가 발생했습니다.
특히 REST 기반 폴링 방식은 매번 요청을 날려야 하다 보니, 메시지가 늦게 도착하고 자원 낭비도 심했습니다.
또 하나 중요한 문제는,
인증되지 않은 사용자가 채팅방에 접근하거나
같은 참여자 조합으로 채팅방이 여러 개 생성되는 문제도 있었습니다.
그래서 이 문제들을 해결하기 위한 구조적인 전환이 필요했습니다.
이 문제들을 해결하기 위해 세 가지 키워드를 중심으로 설계했습니다:
1. 실시간성 확보
2. 보안 강화
3. 채팅방 관리 로직 개선
우선 WebSocket + STOMP 조합을 채택했습니다.
STOMP는 메시지 발행/구독 구조가 명확하고 Spring에서 잘 지원되기 때문입니다.
SockJS는 WebSocket을 지원하지 않는 환경에서도 fallback을 제공하기 때문에 안정성 측면에서도 좋았습니다.
인증 문제는 JWT 기반의 HandshakeInterceptor를 사용했습니다.
WebSocket은 일반 HTTP처럼 필터를 탈 수 없기 때문에, 연결 시점에 토큰을 검증하는 별도의 인터셉터가 필요했습니다.
채팅방 중복 문제는 DB에서 참여자 조합으로 중복 검사를 하도록 로직을 만들었고,
참여자 검증은 ChatParticipant
테이블을 통해 명시적인 관계를 설정해서 처리했습니다.
이제 실제 구현 흐름을 설명드리겠습니다.
연결 단계
클라이언트가 /ws
로 연결을 시도하면,
서버에서는 JwtHandshakeInterceptor
에서 JWT 토큰을 검증합니다.
메시지 전송 단계
인증이 완료되면 클라이언트는 /pub/chat/message
로 메시지를 전송하고,
서버는 이 메시지를 저장한 후, 해당 채팅방 구독자에게 /sub/chat/room/{roomId}
경로로 브로드캐스팅합니다.
채팅방 관리
ChatParticipant
테이블을 통해 체크됩니다.이렇게 흐름이 연결 → 인증 → 메시지 발행 → 저장 및 전파로 이어지며,
모든 과정에서 인증된 사용자만 접근할 수 있도록 보안도 강화했습니다.
도입 전에는 평균 응답 속도가 약 1500ms였지만,
WebSocket 기반으로 전환한 이후에는 수ms 단위로 실시간 반응을 얻을 수 있게 되었습니다.
또한, 폴링 방식의 트래픽 과부하도 없어져서
서버 자원 낭비가 대폭 줄었고, 사용자 입장에서 메시지가 즉시 도착하기 때문에
채팅 UX가 매우 향상됐습니다.
특히, Direct 방 중복 문제를 해결하면서
DB 쿼리의 효율성도 높아졌고,
불필요한 채팅방 생성을 막아 운영 측면에서도 유의미한 개선이 이루어졌습니다.
이번 구현에서 가장 어려웠던 부분은 WebSocket의 인증 처리였습니다.
HTTP와는 다른 흐름이라 필터가 적용되지 않고,
클라이언트 연결 전 인터셉터를 통해 토큰을 검증해야 했기 때문에 구조를 새롭게 이해해야 했습니다.
이 경험을 통해 프로토콜별 동작 흐름을 깊이 이해하게 됐고,
보안과 UX를 동시에 만족시키는 구조가 왜 중요한지도 체감했습니다.
아직 미구현된 기능들도 많습니다.
정리하자면,
이번 프로젝트에서는 단순한 채팅 기능 구현을 넘어서,
실시간성, 인증, 보안, 관리 효율성을 모두 고려한
구조적인 개선을 목표로 했고, 실제로 서비스 품질 향상에 기여한 성과가 있었습니다.
감사합니다.