[AWS] 채팅 시스템 설계 - 1주차

Jiwoo Jung·2025년 5월 13일
0

Amazon Cloud Club

목록 보기
4/6

Amazon Cloud Club Ewha 3기 사이드 프로젝트

Infra 파트를 맡았다.
이번주는 채팅 시스템 위한 Websocket 스터디, 유저 시나리오 작성, 아키텍처 초안 작성을 진행했다.


0. 주제 및 요구사항

주제
채팅 시스템 설계

요구사항

  • 보안적으로 안전하도록 구성한다.
  • 캐시(ElastiCache) 사용 권장
  • 가용성 및 안정성을 높인다.
  • AWS의 서비스들을 최대한 활용하여 운영비용을 절감한다.
  • $40 ~ $60 사이의 비용을 사용한다.
  • 최소한의 기능을 완성도 있게 구현한다.

인프라 요구사항

  • 평균적으로 약 1000명의 유저가 해당 서비스를 사용
    • 최대 동시 접속 사용자 수 500명 예상
  • 초당 약 50건의 메시지 전송 처리 필요
  • 최대 6개월간 메시지 내역 보관 필요
  • 메시지 전송 지연 시간은 2초 이내

심화 요구사항

  • 그룹 채팅 지원: 최대 100명까지 참여 가능한 그룹 채팅방 제공
  • 첨부 파일: 채팅에서 최대 10MB 크기의 파일 첨부 기능 지원
  • 오프라인 메시지 처리: 사용자가 오프라인 상태일 때 메시지 저장 및 재접속 시 동기화
  • 멀티 디바이스 지원: 동일 계정으로 최대 3개 기기 동시 접속 지원 (동일 계정 접속 수 제한)

1. Websocket 스터디

inpa.tistory.com

필요성

  • HTTP는 클라이언트의 요청이 있어야 서버가 응답 → 새로운 정보를 얻기 위해 항상 새로운 URL 요청
    • Polling 방식으로 채팅 구현할 수 있지만, 단방향 통신의 한계
  • 웹이 발전하며 더 동적인 표현과 상호작용이 필요해짐
  • “실시간 양방향 통신” 필요

웹소켓이란?

  • HTML5 표준 기술
  • 클라이언트(브라우저)와 서버 사이 동적인 양방향 채널 구성
  • Websocket API 로 사용
  • 최초 연결은 HTTP로 연결, 그 후로 지속적인 양방향 통신 가능


AWS Websocket API

API Gateway의 WebSocket API 개요 - Amazon API Gateway

자습서: WebSocket API, Lambda 및 DynamoDB를 사용하여 WebSocket 채팅 앱 생성 - Amazon API Gateway

자습서: AWS 통합을 통해 WebSocket API 생성 - Amazon API Gateway

WebSocket API, Lambda 및 DynamoDB를 사용하여 AWS 서비스만을 통해 서버리스 WebSocket 채팅을 구현할 수 있다.


2. 유저 시나리오

이때는 프론트엔드가 없었기에, 백엔드 관점에서 작성했다.

회원가입 및 로그인 - REST API
- 사용자 A는 이름, 이메일, 비밀번호 등 최소한의 정보를 입력하여 회원가입을 진행한다.
- 클라이언트는 사용자 정보를 `POST /signup` API로 서버에 전송하고, 서버는 이를 저장 후 성공 응답을 반환한다.
- 이후, A는 로그인 화면에서 이메일과 비밀번호를 입력하고 `POST /login` API를 통해 인증 요청을 보낸다. 이때 비밀번호는 해싱하여
- 서버는 인증이 성공하면 JWT 토큰 또는 세션 토큰을 발급하며, 클라이언트는 이를 저장해 이후 요청에 인증 헤더로 포함한다.
- 로그인 후 사용자 A는 인증 토큰을 기반으로 WebSocket 연결을 시작하거나, REST API를 통해 채팅 이력을 조회할 수 있다.

1:1 채팅 - WebSocket

- 사용자 A는 서버와 WebSocket 연결을 수립한다.
- 사용자 B도 별도로 WebSocket 연결을 수립해 있는 상태다.
- A가 메시지를 작성하고 WebSocket을 통해 메시지를 전송한다.
- 서버는 메시지를 저장한 뒤, B의 WebSocket 세션을 확인해 2초 이내에 메시지를 푸시(PUSH)한다.
- B가 실시간 응답을 보내면 동일한 흐름으로 A에게 전송된다.

그룹 채팅 - WebSocket

- 사용자 A는 WebSocket을 통해 그룹 채팅방을 만든다.
- 그룹 생성 후, A가 메세지를 전송한다.
- 서버는 해당 메시지를 저장한 뒤, 그룹 참가자(B, C)의 연결된 WebSocket 세션을 찾아 동시에 브로드캐스팅한다.
- 각 수신자는 동일한 시간 내 (2초 이내)에 메시지를 수신한다.

메시지 이력 조회 - REST API

- 사용자 A가 채팅방에서 이전 대화를 확인하고자 할 때, `GET /chat/history?chat_type=group&chat_id=g123&limit=50` 형태의 API를 호출한다.
- 서버는 캐시 저장소 또는 백업된 저장소(DB)에서 해당 채팅방 ID에 대응하는 메시지를 역순으로 페이징 조회한다.
- 클라이언트는 받은 메시지를 타임스탬프 기준으로 정렬해 사용자에게 출력한다.
- 이 API는 WebSocket 세션이 종료된 상태에서도 호출 가능하며, 과거 6개월 이내 데이터가 반환된다.

네트워크 불안정 대응

- 사용자 A가 메시지를 보내는 도중 연결이 끊기면, WebSocket 클라이언트는 자동으로 재연결을 시도한다.
- 재연결 후, 미확인 메시지를 다시 서버에 전송한다 (`message_id` 포함).
- 서버는 `message_id` 또는 타임스탬프를 기준으로 중복 메시지를 식별하고, 중복 없이 저장 및 전송한다.
- 메시지는 수신자에게 정상적으로 도착한다.

최종 유저 시나리오

팀원들이 작성해준 최종 유저 시나리오는 다음과 같다.

1. 회원가입
    - 사용자는 이메일, pw로 회원가입

2. 로그인/로그아웃
    - 사용자는 이메일, pw로 로그인
    - 사용자는 이메일, pw로 로그아웃
    
3. 일대일 채팅
    - 사용자는 프로필 목록에서 채팅할 상대를 선택
    - 혹은 채팅방 목록에서 채팅방을 선택
    - 실시간으로 메시지 전송 및 수신
    - 읽음 확인 및 타이핑 중 표시 기능 제공

4. 다대다 채팅
    - 사용자는 여러 참가자를 초대하여 그룹 채팅방 생성
    - 혹은 채팅방 목록에서 채팅방을 선택
    - 모든 참가자는 참가자 추가/제거 가능
    - 모든 참가자는 메시지를 보내고 받을 수 있음

5. 이전 메세지 조회
    - 채팅방 입장 후, 해당 채팅방의 이전 메세지들 확인 가능
    - (추가 기능) 이미지/파일 첨부 및 공유기능
    - 이전 메세지 검색기능

6. (추가 기능) 브라우저 푸시 메세지
    - 브라우저에 접속해 있을 때 채팅 송신 시 푸시 메세지 팝업

7. (추가 기능) 파일 전송/조회
    - 사용자는 일대일 채팅으로 파일을 전송할 수 있음
    - 사용자는 다대다 채팅으로 파일을 전송할 수 있음

3. 아키텍처 초안

aws 서비스를 최대한 활용하고, 비용을 줄이기 위해 Lambda를 이용한 심플한 아키텍처를 설계했다.

최소 아키텍처


가장 간단한 아키텍처이다. API gateway, Lambda, DynamoDB만을 이용하여 채팅을 구현한다.


캐싱 추가


ElastiCache를 추가했다. ElastiCache를 사용하기 위해 VPC의 private subnet 안에 배치했지만, 서버리스 아키텍처에 안어울린다고 생각했다.


aws.amazon.com
찾아보니 이렇게 서버리스로도 사용할 수 있다고 한다.


Cognito 추가


Cognito를 사용하면 jwt를 사용하지 않아도 되는줄 알고 잘못 그린 것같다.


회의 결과, 백엔드 파트가 직접 서버를 구성하고 WebSocket을 구현해보고 싶어해서 함수단위로 실행하는 Lambda는 사용하지 않기로 했다.
대안은 EC2, ECS등이 있다. ECS Fargate의 경우 서버리스지만, 컨테이너 기반이라 스프링부트 앱을 컨테이너화해서 그대로 올리면 백엔드 입장에선 달라지는게 없는 것 같아서 괜찮은 대안이다.


최종 아키텍처 초안

draw.io에서 aws 2025를 추가하면 쉽게 그릴 수 있다.

네트워크 구성

  • ALB
    HTTPS · WebSocket 트래픽을 Fargate 컨테이너로 분산
  • CloudFront
    CDN 캐시 배포
  • Route53
    도메인 관리, DNS 라우팅
  • NAT Gateway(필요 시)
    프라이빗 서브넷의 Fargate가 외부와 통신

컨테이너 실행 및 배포

  • ECS
    컨테이너 오케스트레이션(서비스, 배포, 헬스체크)
  • Fargate
    Spring Boot 채팅 컨테이너를 서버리스로 실행
  • ECR
    백엔드 도커 이미지 저장소

인증/보안

  • IAM
    ECS/CI/CD/Secrets 권한 제어
  • Secrets Manager
    애플리케이션 설정·DB 자격증명·JWT 서명 키 같은 비밀(Secrets), 파라미터 중앙 관리
  • Cognito
    사용자 인증 및 JWT 발급
    *클라이언트가 인터넷에서 직접 호출, 백엔드는 JWT 검증만 수행 (인터넷 X)

데이터 저장/전송

  • DynamoDB
    Message, RoomMeta, User(TTL 6개월) 저장
  • SQS(or MQ)
    DynamoDB 비동기 쓰기 대기열
  • ElastiCache for Redis
    실시간 메시지 fan‑out, WebSocket 세션 관리
  • S3
    정적 파일, 프론트 자산 저장소

메세지 쓰기 시나리오
1. 클라이언트로 메시지 전송 (실시간)
서버는 먼저 ElastiCache Redis Stream에 메시지를 XADD하여 WebSocket 구독 클라이언트에게 바로 fan-out.
2. 비동기 저장 처리
동시에 메시지를 Amazon SQS에 큐잉 → 백그라운드에서 스프링부트 서버가 읽어 DynamoDB에 영구 저장.
메시지 유실 방지를 위해 XADD 성공 후 SQS 전송까지 완료된 후에만 ACK 처리.

로깅/모니터링

  • CloudWatch
    로그 수집·메트릭·알람

-1

더 공부해야 할 주제

  • ECS Fargate를 선택한 이유
  • ECS Fargate는 서버리스인데, private subnet에 tasks가 생성되어서 어떻게 작동하는지
  • ElastiCache와 ECS Fargate Task는 동일 vpc에 있으니까 nat gateway가 필요 없는지
  • cognito, cloudfront, route53는 언제 어떻게 구성해야 할지
  • 현재의 multi-az 구조가 필요한지
  • cloud watch 사용법
  • sqs/mq를 추가할지 말지, 어떻게 dynamodb와 연결하는지
  • 비용 계산

적다보니 너무 많다..

0개의 댓글