Amazon Cloud Club Ewha 3기 사이드 프로젝트
Infra
파트를 맡았다.
이번주는 채팅 시스템 위한 Websocket 스터디, 유저 시나리오 작성, 아키텍처 초안 작성을 진행했다.
주제
채팅 시스템 설계
요구사항
인프라 요구사항
1000명
의 유저가 해당 서비스를 사용500명
예상50건
의 메시지 전송 처리 필요6개월
간 메시지 내역 보관 필요2초
이내심화 요구사항
100명
까지 참여 가능한 그룹 채팅방 제공10MB
크기의 파일 첨부 기능 지원3개 기기
동시 접속 지원 (동일 계정 접속 수 제한)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 채팅을 구현할 수 있다.
이때는 프론트엔드가 없었기에, 백엔드 관점에서 작성했다.
회원가입 및 로그인 - 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. (추가 기능) 파일 전송/조회
- 사용자는 일대일 채팅으로 파일을 전송할 수 있음
- 사용자는 다대다 채팅으로 파일을 전송할 수 있음
aws 서비스를 최대한 활용하고, 비용을 줄이기 위해 Lambda를 이용한 심플한 아키텍처를 설계했다.
가장 간단한 아키텍처이다. API gateway, Lambda, DynamoDB만을 이용하여 채팅을 구현한다.
ElastiCache를 추가했다. ElastiCache를 사용하기 위해 VPC의 private subnet 안에 배치했지만, 서버리스 아키텍처에 안어울린다고 생각했다.
aws.amazon.com
찾아보니 이렇게 서버리스로도 사용할 수 있다고 한다.
Cognito를 사용하면 jwt를 사용하지 않아도 되는줄 알고 잘못 그린 것같다.
회의 결과, 백엔드 파트가 직접 서버를 구성하고 WebSocket을 구현해보고 싶어해서 함수단위로 실행하는 Lambda는 사용하지 않기로 했다.
대안은 EC2, ECS등이 있다. ECS Fargate의 경우 서버리스지만, 컨테이너 기반이라 스프링부트 앱을 컨테이너화해서 그대로 올리면 백엔드 입장에선 달라지는게 없는 것 같아서 괜찮은 대안이다.
draw.io
에서 aws 2025를 추가하면 쉽게 그릴 수 있다.
메세지 쓰기 시나리오
1. 클라이언트로 메시지 전송 (실시간)
서버는 먼저ElastiCache
Redis Stream에 메시지를 XADD하여 WebSocket 구독 클라이언트에게 바로 fan-out.
2. 비동기 저장 처리
동시에 메시지를Amazon SQS
에 큐잉 → 백그라운드에서 스프링부트 서버가 읽어DynamoDB
에 영구 저장.
메시지 유실 방지를 위해 XADD 성공 후 SQS 전송까지 완료된 후에만 ACK 처리.
더 공부해야 할 주제
적다보니 너무 많다..