Skip to content

HTTP, Socket 서버 분리

이지호 edited this page Jan 7, 2025 · 4 revisions

📄 HTTP/Socket 프로세스 분리

기존 NestJS 애플리케이션의 HTTP와 WebSocket 서버를 별도의 프로세스로 분리하여, 동일 인스턴스에서 3000번과 4000번 포트로 각각 서비스하도록 구현했습니다.

🧩 배경 및 필요성

  • WebSocket 연결이 HTTP 요청 처리에 영향을 주지 않도록 분리가 필요했습니다.
  • 비용 효율성을 위해 새로운 인스턴스 생성 대신 프로세스 분리 방식을 선택했습니다.
  • 프로젝트 마감일을 하루 남긴 상황이었기 때문에 기존 코드베이스를 최소한으로 수정하면서 분리를 진행해야 했습니다.

🔍 기술적 분석 및 비교

  • 서버 분리 방식 검토
    • 새로운 인스턴스에 분리: 완전한 격리가 가능하나 비용 증가
    • 프로세스 분리: 동일 인스턴스 내에서 자원 분리, 비용 효율적
    • 선택: PM2를 활용한 프로세스 분리

🗺️ 문제 해결 과정

1. 설계

image

  • Client1이 질문을 생성하면 HTTP 서버가 응답을 주고, Socket 서버에 브로드캐스트를 요청합니다.
  • Socket 서버는 연결된 Client2, Client3에게 실시간으로 이벤트를 전달합니다.

2. 코드 변경 최소화를 위한 구현

HTTP와 Socket 서버 분리 시 기존 코드의 변경을 최소화하기 위해 다음과 같은 전략을 사용했습니다:

  1. Socket 서버에 HTTP 엔드 포인트 추가

    • Socket 서버에 SocketController를 새로 추가해 '/api/socket/broadcast' 엔드포인트를 만듭니다.
    • 이 엔드포인트는 HTTP 서버로부터 브로드캐스트 요청을 받아 처리합니다.
    • 요청받은 event 타입에 따라 적절한 브로드캐스트 함수를 호출해 연결된 클라이언트들에게 이벤트를 전달합니다.
  2. HTTP 서버에서 Socket 서버로 요청보내는 로직 추가

    • HTTP 서버에서 Socket 서버로 이벤트를 전달하기 위한 유틸리티 함수를 추가합니다.
    • 질문 생성, 수정, 삭제 등의 이벤트가 발생할 때마다 이 유틸리티를 통해 Socket 서버에 브로드캐스트를 요청합니다.
    • QuestionsController 등 기존 컨트롤러의 로직은 그대로 유지하면서 이벤트 전달 부분만 requestSocket으로 교체했습니다.
    //기존 브로드캐스트 로직
    this.socketGateway.broadcastNewQuestion(sessionId, token, resultForOther);
    //수정된 브로드캐스트 로직
    const event = SOCKET_EVENTS.QUESTION_CREATED;
    await requestSocket({ sessionId, token, event, content: resultForOther });

3. server/main.ts의 bootstrap 시작점 수정

if (args.includes('http')) {
  bootstrap(Number(process.env.API_SERVER_PORT ?? '3000'));
} else if (args.includes('ws')) {
  bootstrap(Number(process.env.SOCKET_SERVER_PORT ?? '4000'));
}

4. package.json 스크립트 추가

  "scripts": {
    //중략
    "start:prod:http": "node dist/main http",
    "start:prod:ws": "node dist/main ws",
  },

5. PM2 설정

module.exports = {
  apps: [
    {
      name: 'http-server',
      script: 'pnpm',
      args: 'run start:prod:http',
      interpreter: 'none',
      env: { PORT: 3000 }
    },
    {
      name: 'ws-server',
      script: 'pnpm',
      args: 'run start:prod:ws',
      interpreter: 'none',
      env: { PORT: 4000 }
    }
  ]
};

6. GitHub Actions 배포 자동화

# pm2로 기존 프로세스 종료 및 새 프로세스 시작
pm2 stop all || true
pm2 delete all || true
pnpx prisma generate
pnpx prisma migrate deploy
pnpm build
pm2 start ecosystem.config.js

📈 결과 및 성과

  • 서버 분리로 인한 주요 이점
    • HTTP/WebSocket 서버를 독립적으로 운영할 수 있습니다.
    • 프로세스 분리로 안정성이 향상됩니다.
    • 기존 코드베이스 최소 수정으로 구현을 완료했습니다.
  • 향후 개선 사항
    • 무중단으로 재시작될 수 있도록 도전해볼 계획입니다.
    • 소켓 서버가 수평확장 가능한 구조가 될 수 있도록 해볼 계획입니다.
Clone this wiki locally