FanUP은 비대면 팬미팅 플랫폼입니다.
해당 시리즈는 프로젝트를 진행하며 겪은 설계 고민, 트러블 슈팅 과정에 대해 다룹니다.
프로젝트를 진행하며 FanUP 서비스의 가장 핵심이 되는 선착순 티켓팅 기능을 구현하게 되었습니다.
기획 단계부터 해당 기능에 대해 자세히 다뤄보고 싶었기에 그 과정을 글로 남겨보고자 합니다.
티켓팅 기능에 관한 글은 3부작으로 작성할 예정입니다.
- 티켓팅 기능 설계
- 기능 구현과 부하 테스트
- 성능 개선을 위한 캐시 도입기
우리가 영화를 보기 위해 영화관 좌석을 예매하듯, 티켓팅 기능은 팬미팅에 참여하기 위해 입장권을 구매하는 과정입니다. 프로젝트의 핵심 로직이다보니 다른 기능과도 연결된 부분이 많아 설계 과정에서부터 많은 고민을 했습니다.
티켓팅을 진행하기 위한 선행 조건으로는 팬미팅 이벤트가 생성되어야 합니다.(=티켓 개설)
팬미팅의 경우 아티스트
가 이벤트를 등록 및 수정할 수 있으며 이벤트를 등록할 때, 다음과 같은 정보들을 지정하게 됩니다.
위 내용을 바탕으로 설계한 유저(팬
)가 팬미팅에 참가하기까지의 시나리오는 다음과 같습니다.
(보라색으로 표시된 부분이 팬
이 참여하는 시나리오입니다.)
전체적인 흐름을 살펴봤으니 이제 티켓팅 기능에 대해 집중적으로 살펴보겠습니다.
티켓팅 기능은 스파이크성 대량 트래픽이 유입되는 상황을 가정하였기에 처리 속도를 줄이기 위해 로직을 최대한 분리하였습니다. 따라서 티켓팅 기능에서는 오로지 유저의 티켓 구매 여부만을 판단합니다.
- 티켓팅 시작 시간부터 팬미팅 시작 시간 전까지 티켓 구매가 가능하다.
- 티켓팅 성공 인원 수는 팬미팅 등록 시 정해진 최대 참여 인원을 초과해서는 안된다.
- 동일 티켓은 1인당 1장만 구매가 가능하다. (중복 구매 불가)
위 요구사항을 토대로 정의한 기능 플로우는 다음과 같습니다.
사실 티켓팅 성공 이후에 팬미팅 참여 링크를 발급하는 로직과 해당 로직을 어느 시점에서 실행해야 하는지에 대한 논의도 오래 진행했지만 해당 글의 주제에 부합하지 않는거 같아 제외했습니다. 해당 부분은 나중에 기회가 된다면 따로 작성해보겠습니다.
(혼란했던 논의 과정이 궁금하시다면..)
precondition: login 한 유저
POST /ticket-user
body {
ticketId: number
}
현 프로젝트는 MSA
와 API Gateway Pattern
을 도입하였기에 티켓팅 기능을 구현하는 티켓 서비스로 전달되는 요청은 모두 유효한 user
라는 것이 보장됩니다. 또한 gateway에서 각 마이크로 서비스를 호출하는 경우 user id
를 파라미터로 함께 보내주기 때문에 요청에는 해당 내용이 포함되지 않습니다.
FanUP의 MSA
도입기가 궁금하시다면 이 글을 참고해주세요.
{
statusCode: 201,
message: "Ticketing success"
}
{
statusCode: 400,
message: "All tickets are sold out"
}
유저가 티켓을 구매하는 시나리오 중, 가장 첫 단계는 현재 구매 가능한 티켓 리스트를 조회하는 것입니다. 여기서 구매 가능한 티켓이란 티켓의 잔여 수량
이 남아있으며 현재 시간
이 해당 티켓에 대한 팬미팅 시작 시간
보다 30분 이전
인 경우를 뜻합니다.
따라서 티켓의 잔여 수량
이 없어 티켓팅을 실패하는 경우 파라미터로 전달되는 ticketId
가 유효하지 않다고 판단해 400 에러
를 반환하도록 했습니다.
티켓팅 기능을 담당하는 티켓 서비스의 ERD입니다.
각 테이블 및 컬럼에 대한 설명은 다음과 같습니다.
Ticket: 팬미팅에 참가하기 위한 티켓 정보를 저장
칼럼명 | 설명 |
---|---|
id | 티켓 고유 id |
title | 티켓 이름 |
content | 티켓 설명 |
artistId | 해당 티켓을 발행한 아티스트의 id |
salesTime | 티켓 판매 시작 시간 |
startTime | 팬미팅 시작 시간 |
totalAmount | 티켓 총 수량 |
numberTeam | 한 팀 당 최대 인원 |
timeTeam | 한 팀 당 팬미팅 진행 시간 |
price | 티켓 가격 |
UserTicket: 티켓팅을 성공한 유저의 정보를 저장
칼럼명 | 설명 |
---|---|
id | 고유 id |
userId | 해당 티켓을 구매한 user의 id |
ticketId | 해당 티켓의 id |
fanupId | 팬미팅에 참여하기 위한 방의 id |
Artist: 아티스트의 정보를 저장
칼럼명 | 설명 |
---|---|
id | 고유 id |
name | 아티스트의 이름 |
profileUrl | 프로필 사진의 url |
티켓팅 기능만 놓고 보면 비교적 간단한 플로우를 가지고 있습니다.
하지만 우리는 해당 기능이 스파이크성 대량 트래픽을 감당해야하는 예상 시나리오를 세웠습니다.
다음 편에서는 기능 구현 과정에서 기능이 안정적으로 동작하는지 확인하기 위해 부하 테스트를 진행하며 단일 서버 + RDB 기준 최대 throughput과 응답시간을 살펴볼 예정입니다.