🧩 내가 구현한 기능
- WebSocket 기반 실시간 채팅 시스템
- STOMP + SockJS를 활용한 메시지 송수신
- 채팅방 생성, 입장, 메시지 조회, 메시지 전송
- JWT 기반 인증 처리 (핸드셰이크 단계)
📌 주요 로직
- WebSocket 연결 시 JWT 토큰을 HandshakeInterceptor에서 검증
- STOMP 프로토콜을 사용하여 메시지를 발행(/pub)하고 구독(/sub) 처리
- 메시지 전송 시 서버에서 저장 → 해당 채팅방 구독자에게 broadcast
- 채팅방은 그룹 단위로 관리되며, 사용자 참여 여부를 검증
- 과거 메시지는 페이지네이션 처리하여 조회 가능
📂 배경
서비스 내 그룹 기능이 존재하고, 그 그룹 단위로 실시간 채팅 기능이 필요했습니다.
단순 REST API 기반의 폴링 방식은 지연 시간과 트래픽 낭비가 심해 WebSocket 기반으로 전환할 필요성이 있었습니다.
🧠 의사결정
🔍 문제 정의 (Why)
- REST API 기반으로는 실시간성을 보장하기 어려움
- 인증되지 않은 사용자의 WebSocket 접근을 차단해야 함
- 동일한 참여자로 Direct 방이 중복 생성되는 문제
🛠 해결 방법 & 기술 선택 (How)
문제 | 해결 방법 | 선택 이유 |
---|
실시간성 | WebSocket + STOMP | 널리 쓰이고 안정적인 메시징 프로토콜 |
인증 처리 | HandshakeInterceptor + JWT | WebSocket은 Filter를 타지 않기 때문에 인터셉터 필요 |
Direct 방 중복 | 참여자 조합 기준 중복 검사 | DB에서 참여자 수 기준 그룹핑하여 중복 여부 확인 |
참여자 검증 | ChatParticipant 테이블로 검증 | 명시적인 관계로 보안 강화 및 확장성 확보 |
🔄 흐름 구조도 (요청 → 처리 → 응답)
- 클라이언트:
/ws
로 연결 요청 (SockJS)
- 서버:
JwtHandshakeInterceptor
에서 JWT 검증
- 연결 성공 후 → 클라이언트가
/pub/chat/message
로 메시지 전송
- 서버:
- 메시지 저장
- 해당 채팅방 구독 경로
/sub/chat/room/{roomId
}로 broadcast
- 클라이언트는
/sub/chat/room/{roomId}
구독 상태로 실시간 수신
📌 회고
✅ 장점
- REST API와는 비교할 수 없는 실시간 반응성 확보
- STOMP를 통한 메시지 발행/구독의 명확한 구분
- 인증된 사용자만 접근 가능하도록 보안 강화
- 채팅 메시지 DB 저장 → 추후 검색, 읽음 처리 등 확장 가능
❌ 단점 및 한계
- WebSocket은 초기 진입 장벽이 있음 (인증, 오류 핸들링 등)
- 클러스터 환경에서는 Redis Pub/Sub 또는 MQ 연동 필요
- 읽음 처리, 메시지 삭제 등의 기능은 아직 미구현
📈 개선 및 성능 비교 (도전 항목)
항목 | 구현 전 (REST 폴링) | 구현 후 (WebSocket) |
---|
평균 응답 시간 | 약 1500ms | 실시간 (수ms 단위) |
트래픽 | 초당 수십 회 요청 | 연결 유지 방식으로 절감 |
유저 반응 | 폴링 시 지연 느낌 존재 | 메시지 수신 즉시 표시됨 |
🔧 향후 개선 방향
- Redis 기반의 메시지 브로커 연동으로 수평 확장
- 메시지 읽음 처리 및 알림 연동
- 채팅방 내 참여자 목록, 강제 퇴장 기능 등 UX 개선
- WebSocket 연결 실패 대비 fallback 처리 강화