실시간 채팅 서버 개발 - 02 (방 생성하기)

2026. 1. 18. 10:17·NestJS/개발

이전 프로젝트 정리

앞선 포스트에서는 NestJS 기반 채팅 서버에서 Redis를 도입하고, 기본적인 Redis 연결과 서비스 구조를 구성하는 과정까지 정리했다. 하지만 Redis를 붙였다고 해서 곧바로 소켓 채팅이 완성되는 것은 아니다. 실제 채팅 시스템에서는 소켓 연결 이전에 반드시 HTTP 레벨에서 관리해야 할 상태들이 존재한다. 대표적으로 방 생성, 방 입장 가능 여부 판단, 현재 인원 수 관리와 같은 로직이다. 이러한 작업을 소켓 이벤트 내부에서 처리하게 되면, 연결 시점마다 불필요한 복잡도가 증가하고 예외 처리 또한 까다로워진다. 그래서 이번 포스트에서는 Redis를 활용해 채팅방의 상태를 HTTP API로 먼저 관리하고, 검증이 끝난 이후에만 WebSocket join 이 이루어지도록 전체 흐름을 설계해본다.

구체적으로는 다음과 같은 순서로 진행한다.

  • HTTP API로 채팅방 생성
  • 방 입장 시 Redis 기반 인원 수 증가 및 최대 인원 검증
  • 검증이 완료된 이후에만 Socket.io room join 처리
  • 방 나가기 시 인원 수 감소 (마지막 체크 부분)

위의 과정을 통해 채팅 서버에서 상태 관리(HTTP)와 실시간 통신(Socket)의 책임을 명확히 분리하고, 확장성과 안정성을 고려한 구조를 만들어보려고 한다.


방 생성하기

import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { randomUUID } from 'crypto';
import { RedisService } from 'src/redis/redis.service';

enum RoomStatus {
  WAIT = 'WAIT',
  PLAYING = 'PLAYING',
  END = 'END',
}

@Injectable()
export class RoomService {
  // 레디스 서비스 만들어둔거 의존성 주입
  constructor(private readonly redis: RedisService) {}

  async createRoom(): Promise<{ roomId: string }> {
    const uuidRoom: string = randomUUID();
    const key = `room:${uuidRoom}`;
    const time: number = 60 * 30;
    const maxPlayer = 4;

    await this.redis.client.hset(key, {
      status: RoomStatus.WAIT,
      players: 0,
      maxPlayers: maxPlayer,
      created: Date.now().toString(),
    });

    await this.redis.client.expire(key, time);

    return { roomId: uuidRoom };
  }
}

1. 방 식별자 생성하기

const uuidRoom: string = randomUUID();

 

  • 방 ID 충돌 가능성 제거
  • 서버 인스턴스 수와 무관한 고유성 보장
  • 소켓 room 이름으로도 그대로 사용 가능

2. Redis Key 구조 설계

const key = `room:${uuidRoom}`;
  • 방 상태를 하나의 Key로 묶어 관리 가능
  • 필드 단위 업데이트가 쉬움
  • 문자열 기반이라 디버깅이 용이함

3. 방 초기 상태 정의하기

enum RoomStatus {
  WAIT = 'WAIT',
  PLAYING = 'PLAYING',
  END = 'END',
}

await this.redis.client.hset(key, {
  status: RoomStatus.WAIT,
  players: 0,
  maxPlayers: maxPlayer,
  created: Date.now().toString(),
});

 

이렇게 초기 상태를 명확히 정의함으로써 입장 가능 여부, 게임 시작 조건, 방 만료 처리 등을 모두 Redis 상태만으로 판단할 수 있다.


4. TTL 기반 방 생명주기 관리

const time: number = 60 * 30;
await this.redis.client.expire(key, time);

 

  • 기본 유지 시간: 30분
  • 사용자가 아무도 입장하지 않아도 자동 삭제
  • 서버 재시작과 무관하게 정리 가능

5. TTL 만료에 대한 생각?

TTL 만료 시간에 대해 생각할 때, 단순히 "일정 시간이 지나면 방이 삭제된다"는 관점만으로 접근하는 것은 위험하다. 채팅방이나 게임방은 단순한 데이터가 아니라 실시간으로 사용 중인 상태(State)를 가진 리소스이기 때문이다. 만약 게임이 진행 중인 상황에서 Redis의 TTL이 만료되어 방 정보가 삭제된다면, 이는 단순한 삭제 문제가 아니다. 서버 입장에서는 게임의 현재 상태를 한순간에 잃어버리는 치명적인 상황이 된다. 그래서 결론적으로 "방을 언제 삭제할 것인가"를 결정하는 수단이 아니라, 방의 상태에 따라 생명주기를 제어하는 도구로 다뤄져야 한다.


현재 생각하고 있는 방 생성주기 관리

[HTTP] 방 생성 요청
        |
        v
+-----------------------------+
| room:{roomId} 생성          |
| status = WAIT               |
| players = 0                 |
| maxPlayers = N              |
| TTL = 30분                  |
+-----------------------------+
        |
        | (유저 입장)
        v
+-----------------------------+
| status = WAIT               |
| players 증가                |
| TTL 유지                    |
+-----------------------------+
        |
        | (게임 시작 조건 만족)
        v
+-----------------------------+
| status = PLAYING            |
| TTL 제거 (PERSIST)          |
| 자동 삭제 방지               |
+-----------------------------+
        |
        | (게임 진행 중)
        v
+-----------------------------+
| 상태 유지                   |
| Redis key 영구 유지         |
+-----------------------------+
        |
        | (게임 종료)
        v
+-----------------------------+
| status = END.            |
| TTL 재설정 (예: 30분)       |
+-----------------------------+
        |
        | (TTL 만료)
        v
+-----------------------------+
| room:{roomId} 자동 삭제     |
| 리소스 정리 완료              |
+-----------------------------+

 

 

 

'NestJS > 개발' 카테고리의 다른 글

실시간 채팅 서버 개발 - 03 (방 접속하기)  (1) 2026.01.19
실시간 채팅 서버 개발 - 01 (Redis 및 NestJS 셋팅)  (1) 2026.01.14
Redis/BullMQ 이용하여 연산 작업 따로하기  (0) 2025.12.23
JWT - Passport 사용하기  (0) 2025.12.22
JWT - 역할 기반 관리하기  (1) 2025.12.21
'NestJS/개발' 카테고리의 다른 글
  • 실시간 채팅 서버 개발 - 03 (방 접속하기)
  • 실시간 채팅 서버 개발 - 01 (Redis 및 NestJS 셋팅)
  • Redis/BullMQ 이용하여 연산 작업 따로하기
  • JWT - Passport 사용하기
나는지토
나는지토
  • 나는지토
    안녕은헬로입니다.
    나는지토
  • 전체
    오늘
    어제
    • 분류 전체보기 (27)
      • Backend Design (1)
      • NestJS (19)
        • 개발 (9)
        • 개념과 구조 정리 (10)
      • SpringBoot (0)
      • Java (4)
        • 코테 (0)
      • PostgreSQL (2)
      • Docker (1)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    인증 가드
    Java
    채팅
    ArrayList
    PostgreSQL
    토큰 검사
    JWT
    Collections
    역할 검사
    Redis
    코딩테스트
    커서기반 조회
    컨트롤러
    nestjs/jwt
    nestjs
    서비스
    자료구조
    db 연결 오류
    BullMQ
    조회 방식
  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
나는지토
실시간 채팅 서버 개발 - 02 (방 생성하기)
상단으로

티스토리툴바