사용자가 축제를 쉽고 직관적으로 예약하고, 참여자들과 정보를 공유하며 실시간 소통할 수 있는 종합 축제 예약 플랫폼
- 회원가입, 로그인
- 축제 정보 제공
- 축제 예약
- 채팅 시스템
- 축제 검색
- 마이페이지
- 축제 알림
- Tech Stack
- Spring Boot, Spring JPA, Apache Kafka, Redis, Stomp, FCM, AWS EventBridge, AWS SNS, AWS SQS
- DB
- AWS RDS(MySQL), AWS ElastiCache, DynamoDB
- Infra
- AWS EC2 Auto Scaling, AWS ALB, AWS VPC
- DevOps
- AWS Code Deploy, AWS ECR, AWS S3, Github Actions, Docker
- 아키텍처 설계
- 인프라 프로비저닝
- CI/CD 파이프라인 구축
- 채팅 시스템 구현
고가용성, 확장성, 보안, 재해 복구(DR) 을 고민하며 다음과 같은 아키텍처를 구성했습니다.
- 단일 장애점을 방지하고 자동으로 장애를 조치하는 Multi AZ 배포
- EC2, RDS, ElasticCache를 Multi AZ로 배포해 한 인스턴스가 장애를 겪더라도 다른 인스턴스가 운영을 이어나가 서비스 중단을 방지하는 아키텍처로 설계했습니다.
- 고가용성과 확장성을 위한 트래픽 분산 아키텍처
- 대규모/스파크 트래픽을 ELB가 여러 가용영역의 여러 EC2 인스턴스로 분배하여 특정 인스턴스가 트래픽에 의해 다운되는 것을 방지합니다.
- 스케일링 정책에 따라 인스턴스의 CPU 사용량이 70%를 초과하면 자동으로 확장해 트래픽을 수용하게 하였습니다.
- 데이터베이스는 접근을 엄격하게
- RDS, ElasticCache, MSK Broker는 EC2와 다른 프라이빗 서브넷에 배포되어, EC2 인스턴스를 통해서만 접근 가능하도록 보안 그룹을 구성하였습니다. 이를 통해 인터넷으로부터의 직접적인 접근이 차단되며, ELB와 직접적으로 통신하지 않기 때문에 보안이 강화되었습니다.
- Github Action, AWS ECR, Code Deploy를 활용한 Blue/Green 무중단 배포 파이프라인 구성
- Blue/Green이란 대체 인스턴스(Green)를 생성해 배포하는 과정에서 원본 인스턴스(Blue)를 유지하고, 배포가 완료되면 트래픽을 전환한 후 Blue 그룹을 안전히 제거함으로써 배포 과정에서 서버가 중단되지 않는 배포 방식
- 롤링/블루그린 방식 중 블루그린을 채택한 이유는 롤링에 비해 배포 실패 시 롤백이 쉽고 빠르다는 점이였으며, 그린 그룹의 안정성이 확인되면 블루 그룹은 빠르게 삭제해 비용 효율을 챙겼습니다.
- 여러 명이 동시에 작업 중일 때도 배포로 인해 서버가 중단되지 않아 개발 효율이 증진됨
분산 서버 환경에서 채팅 시스템의 요구사항은 다음과 같습니다.
- 실시간으로 메세지를 송수신 해야 합니다.
- 메세지의 정확성을 보장 해야 합니다.
- 대규모 데이터인 메세지를 빠르게 로드 해와야 합니다.
이 3가지 조건을 각각 다음과 같은 구성으로 만족시켰습니다.
-
채팅에 자주 사용되는 STOMP를 사용해 구현했습니다.
-
기본적으로 STOMP는 내장 메세지 브로커를 사용해 메세지 상태(순서, 채팅방 정보 등)을 서버 메모리에 저장합니다.
-
그러나 분산 서버 환경에선 서버 간 구독 정보가 공유되지 않기 때문에 내장 메세지 브로커를 사용할 수 없습니다. 따라서 분산 서버 환경에선 중앙 집중 메세지 브로커가 필요합니다.
-
분산 서버 환경에서 메세지의 순서, 채팅방 등 정확성을 보장하기 위해 중앙 집중 메세지 브로커인 카프카를 도입했습니다.
-
STOMP의 메세지 브로커 역할을 카프카가 대신함으로써 분산된 서버의 각 사용자들에게 정확하게 메세지를 전달할 수 있게 되었습니다.
-
또한, 카프카의 특성인 파티션과 컨슈머 그룹을 이용해 메세지를 병렬로 처리하기 때문에 대규모 트래픽을 안정적으로 처리할 수 있게 되었습니다.
-
추가적으로, DB 저장용 컨슈머 그룹과 Websocker 전달용 컨슈머 그룹을 분리해 DB 저장 과정에서 병목 현상이 발생해도, 사용자가 실시간으로 메세지를 전달 받는 데 영향을 끼치지 않게 설계했습니다.
3. 대규모 데이터 로드
-
채팅 메세지 내역은 대규모 데이터이기 때문에 RDS만으로는 빠른 처리가 불가하다고 판단했습니다.
-
따라서 Key-Value 기반의 DynamoDB에 메세지 데이터를 저장하여 빠르게 데이터를 로드해오게 구현하였습니다.
-
읽지 않은 메세지 알림을 구현하였습니다.
-
이를 위해 채팅방 온라인 유저와 오프라인 유저를 구별해야 했는데, 이는 채팅방 입장/퇴장 시마다 호출되는 메서드이어야 하므로 사용자 경험을 위해선 빠른 처리와 RDS 부하 감소가 필수였습니다.
-
따라서 Redis가 온라인/오프라인 유저 관리와 알림 개수 계산을 담당하게 구현하였습니다.
-
메모리 관리를 위해 Redis의 TTL은 1시간으로 지정하였습니다.