이전 글에서는 Go 언어 기반 채팅 서버에 PostgreSQL과 MongoDB를 함께 사용하는 이유를 설명하였다. 이번 글에서는 여기에 Redis를 추가하여 성능과 실시간성을 극대화한 3-Tier Persistence 구조를 소개한다.
Redis는 메모리 기반의 고속 키-값 저장소로, Pub/Sub, 캐싱, 세션 저장소 등 다양한 실시간 기능을 제공한다.
각 DB가 담당하는 역할은 다음과 같다:
| 계층 | 저장소 | 주 역할 |
|---|---|---|
| 실시간 계층 | Redis | 실시간 메시지 중계, 읽음 상태, 유저 presence |
| 반정형 계층 | MongoDB | 메시지 로그 저장 (비정형, 대량) |
| 정형 계층 | PostgreSQL | 사용자, 채팅방, 메타 정보 저장 (정형, 관계형) |
이 구조는 다음과 같은 장점을 갖는다:
// 발신자 메시지를 Redis Pub 채널로 전송
redisClient.Publish(ctx, "chatroom:{id}", serializedMessage)
// 수신자는 해당 채널을 구독하여 메시지를 수신
sub := redisClient.Subscribe(ctx, "chatroom:{id}")
msg, _ := sub.ReceiveMessage(ctx)
메시지는 MongoDB에 영속 저장하면서, Redis를 통해 실시간 브로드캐스트됨.
redisClient.HSet(ctx, "user:{id}:session", "online", true)
redisClient.Expire(ctx, "user:{id}:session", time.Minute*5)
ZADD로 관리redisClient.ZAdd(ctx, "chatroom:{id}:read_status", redis.Z{
Score: float64(time.Now().Unix()),
Member: userID,
})
[ Client ]
↓ WebSocket
[ Go 채팅 서버 ]
┣ Redis (실시간 중계 및 상태)
┣ MongoDB (메시지 저장)
┗ PostgreSQL (유저/채팅방 관리)
메시지 발신 시 흐름:
| 항목 | 효과 |
|---|---|
| 응답 속도 | Redis 덕분에 실시간 메시지 처리 가능 |
| 확장성 | MongoDB로 메시지 저장 구조의 유연성 확보 |
| 정합성 | PostgreSQL로 사용자 및 권한 관계 정확히 관리 |
| 유지보수 | 역할별 분리된 DB 구조로 책임 명확화 |
결과적으로 Redis, MongoDB, PostgreSQL의 3-Tier 구조는 실시간성과 정합성, 확장성을 동시에 충족하는 채팅 서버 아키텍처의 이상적인 구현이다.
읽음 상태, presence 등의 임시 데이터는 TTL(Time To Live)을 활용하여 주기적으로 만료 처리한다. 이를 통해 메모리 점유율을 최소화하고, 별도의 정리 작업 없이 상태 유지가 가능하다.
redisClient.Set(ctx, "user:{id}:online", true, time.Minute*3)
3-Tier Persistence 아키텍처는 다음과 같은 환경에 특히 유효하다.
추후에는 Kafka를 통한 메시지 스트리밍 처리 구조와 연결하여, 메시지 저장 및 분석 로직까지 비동기적으로 분리하는 구조도 고려할 수 있다.