WebSocket + Redis 기반 실시간 사용자 추적 시스템 설계

shjk·2025년 4월 8일

1. 개요

WebSocket은 클라이언트-서버 간 지속적인 연결을 유지하며 실시간 양방향 통신을 제공한다. 그러나 다중 서버 환경에서는 단일 서버 메모리만으로 사용자의 접속 상태(online/offline)를 추적할 수 없다. 이 문제를 해결하기 위해 Redis를 활용한 중앙 집중형 세션 관리가 필요하다.

✅ 핵심 목표: 분산 서버 환경에서도 사용자 접속 상태를 일관되게 추적 및 브로드캐스트 가능하게 설계


2. 시스템 아키텍처

┌──────────────┐
│  Web Client │
└──────┬───────┘
       │ WebSocket 연결
┌──────▼──────┐              ┌──────────────┐
│ WebSocket  │──────────────▶             │
│ Server     │ Redis Pub/Sub│  Redis DB   │
│ (N개 서버)  ◀──────────────│             │
└─────────────┘              └──────────────┘
       │
       ▼
유저별 실시간 브로드캐스트 및 상태 추적

3. Redis를 사용하는 이유

목적설명
접속 유저 상태 공유여러 서버가 Redis를 통해 유저의 접속 여부를 공유 가능
서버 간 메시지 브로드캐스트Pub/Sub 기능으로 WebSocket 메시지를 다른 서버로 전달
중앙 세션 저장소유저 상태, 마지막 활동 시간 등을 저장

4. 핵심 로직 흐름

1. 클라이언트 WebSocket 연결 시

conn, _ := upgrader.Upgrade(w, r, nil)
userID := extractUserIDFromJWT(r)

redisClient.SAdd(ctx, "online_users", userID)
redisClient.Publish(ctx, "user_status", fmt.Sprintf("%s:online", userID))
  • SAdd: Redis Set에 사용자 ID 추가 (현재 접속 중인 사용자 목록)
  • Publish: 상태 변경 이벤트를 모든 서버에 브로드캐스트

2. WebSocket 연결 종료 시

conn.Close()
redisClient.SRem(ctx, "online_users", userID)
redisClient.Publish(ctx, "user_status", fmt.Sprintf("%s:offline", userID))

3. Redis 구독(Pub/Sub) 처리

모든 서버는 Redis의 user_status 채널을 구독하고, 유저 상태 이벤트를 처리한다.

sub := redisClient.Subscribe(ctx, "user_status")

go func() {
	for msg := range sub.Channel() {
		handleUserStatus(msg.Payload) // 예: "user123:offline"
	}
}()

4. 실시간 사용자 목록 조회 API

onlineUsers, _ := redisClient.SMembers(ctx, "online_users")
  • 현재 접속 중인 사용자 목록을 Redis Set에서 조회
  • 캐싱된 데이터이므로 응답 속도도 빠름

5. Redis Key 설계 예시

키 이름타입설명
online_usersSet접속 중인 사용자 ID 저장
user_statusPub/Sub서버 간 접속 상태 이벤트 공유
user:{id}:last_seenString마지막 접속 시간 기록

6. 확장 고려사항

  • TTL 설정: 비정상 종료 시를 대비하여 online_users에 TTL을 설정하거나 Ping 메시지를 주기적으로 송신
  • Heartbeat 구현: 클라이언트에서 일정 주기로 ping 메시지를 전송하고 서버는 이를 Redis에 반영
  • 유저별 다중 디바이스 처리: 사용자 ID마다 여러 소켓 연결을 관리하는 구조 필요 (예: user:{id}:connections)

7. 정리

항목설명
통신WebSocket을 통한 실시간 연결
상태 공유Redis의 Pub/Sub과 Set을 통해 분산된 서버 간 유저 상태 동기화
확장성수평 확장 가능하며, 서버 수가 많아져도 Redis를 통해 일관된 상태 관리 가능
주요 기술WebSocket (Go), Redis Set/PubSub, JWT 기반 인증

8. 수식 표현 (개념 모델링)

사용자 상태 저장 모델

OnlineUsers={u1,u2,...,un}U\text{OnlineUsers} = \{ u_1, u_2, ..., u_n \} \subseteq U

여기서 UU는 전체 사용자 집합, OnlineUsers\text{OnlineUsers}는 현재 접속 중인 사용자 집합이다.

상태 이벤트 흐름

eventuser_i={"user_i:online",if connected"user_i:offline",if disconnected\text{event}_{user\_i} = \begin{cases} \text{"user\_i:online"}, & \text{if connected} \\ \text{"user\_i:offline"}, & \text{if disconnected} \end{cases}

9. 결론

WebSocket과 Redis를 결합함으로써, 단일 서버 한계를 넘는 실시간 사용자 추적 시스템을 구현할 수 있다. 본 방식은 실시간 채팅, 알림, 협업 플랫폼 등에서 접속자 추적의 신뢰성을 보장하며, 수평 확장이 가능하다는 점에서 실무적으로 매우 유용하다.

profile
백엔드 개발자

0개의 댓글