실시간 채팅 시스템은 메시지 전송의 지연 시간(latency)을 최소화하고, 확장성(scalability)을 확보하며, 메시지 신뢰성(reliability)을 보장하는 것이 핵심이다. 이를 위해 WebSocket과 Redis를 조합하여 다음과 같은 구조를 설계할 수 있다:
[Client] ─ WebSocket ─▶ [WebSocket Server]
│
├─ Redis Pub/Sub (chatroom:{id})
│
└─ Redis Storage (message queue, user status)
채널명: chatroom:{roomID}
메시지 저장: chatroom:{roomID}:messages (List 또는 Stream)
접속 유저: chatroom:{roomID}:users (Set)
{
"room_id": "abc123",
"sender_id": "user42",
"message": "안녕하세요",
"timestamp": 1712210000
}
메시지는 JSON 직렬화되어 Redis에 저장되고, WebSocket을 통해 전달됨.
클라이언트가 WebSocket으로 메시지 전송
서버에서 메시지 파싱 후 Redis에 발행
payload := ChatMessage{
RoomID: "abc123",
SenderID: "user42",
Message: "안녕하세요",
Timestamp: time.Now().Unix(),
}
data, _ := json.Marshal(payload)
redisClient.Publish(ctx, "chatroom:"+payload.RoomID, data)
redisClient.RPush(ctx, "chatroom:"+payload.RoomID+":messages", data)
Redis가 Pub/Sub을 통해 모든 서버에 메시지 브로드캐스트
서버는 해당 채팅방의 연결된 클라이언트들에게 메시지를 전송
go func() {
sub := redisClient.Subscribe(ctx, "chatroom:"+roomID)
for msg := range sub.Channel() {
broadcastToClientsInRoom(roomID, msg.Payload)
}
}()
redisClient.SAdd(ctx, "chatroom:"+roomID+":users", userID)
퇴장 시
redisClient.SRem(ctx, "chatroom:"+roomID+":users", userID)
현재 접속자 수 조회
redisClient.SMembers(ctx, "chatroom:"+roomID+":users")
| 키 | 타입 | 설명 |
|---|---|---|
chatroom:{id} | Pub/Sub 채널 | 메시지 브로드캐스트 |
chatroom:{id}:messages | List / Stream | 메시지 기록 저장 |
chatroom:{id}:users | Set | 접속 중인 사용자 ID 목록 |
모든 서버는 각 채팅방에 대한 Redis Pub/Sub 채널을 구독하고 있으며, 하나의 서버에서 보낸 메시지가 전체 서버에 전달된다. 이를 통해 여러 서버에 분산된 클라이언트에게 동일한 메시지를 전달할 수 있다.
List는 간단하고 빠르나, 메시지 ID가 없음Stream은 ID 기반 메시지 보존과 소비가 가능하므로 고급 기능이 필요할 경우 적합redisClient.XAdd(&redis.XAddArgs{
Stream: "chatroom:" + roomID + ":stream",
Values: map[string]interface{}{
"sender": userID,
"message": content,
"timestamp": time.Now().Unix(),
},
})
| 항목 | 설명 |
|---|---|
| 수평 확장 | 모든 WebSocket 서버는 동일한 Redis에 연결되어 있고, Pub/Sub으로 메시지를 동기화 |
| 멀티 디바이스 처리 | 하나의 사용자에 대해 여러 WebSocket 연결 관리 필요 (예: Web + Mobile) |
| 접속 유지 | 주기적인 Ping 메시지 및 연결 상태 모니터링 |
| 메시지 영속성 | Redis에만 의존하지 않고, RDB 또는 MongoDB 등으로 백업 가능 |
클라이언트 가 서버 로 메시지 을 전송하면,
접속 중인 사용자의 집합은 다음과 같이 표현된다.
WebSocket과 Redis를 결합한 실시간 채팅 시스템은 다음과 같은 장점을 가진다:
특히 Redis Pub/Sub은 다중 서버 간 메시지 브로드캐스트를 간단하게 구현할 수 있도록 하며, 실시간 채팅 시스템의 핵심 역할을 수행한다.