발생한 문제(v1)

스크린샷 2024-11-05 14.04.20.png

기존에는 위와 같이 공연장의 좌석을 하나의 테이블로 두었고, 좌석 하나당 하나의 행이 생기도록 하였다.

공연장 하나당 좌석이 1만개를 넘는 일도 흔한데, 이 방식에선 Seat 테이블에 행이 수십~수백만 개나 쌓일 수도 있었다. 그러면서도 서로 간에 중복된 데이터 비중이 많아 비효율적이라 생각했다.

그리고 각 좌석이 어디에 위치한 것인지 나타내기 위해 좌표 데이터를 같이 갖고 있게 했는데, 이 역시 굳이 다 저장을 해야 할까 싶은 비효율을 느꼈다.

우리가 규칙을 정해 저장하면 이런 식의 명시적인 데이터 저장을 동반하지 않고도 좌석 위치를 특정할 수 있겠다고 생각했다.

해결(v2)

압축식으로 개선한 스키마:

image.png

중복되는 데이터 저장을 줄이고, join 횟수를 줄이는 스키마를 위와 같이 재설계했다.

주요 변경 사항은:

자세한 설계 내용:

UX 컨셉:

멜론 티켓 서비스의 좌석 표현 방식을 일부 따라한다.

우측 전체 오버뷰를 보면 실제 물리적 구역은 곡선으로 휘어 있다. 그러나 멜론은 이를 모두 직사각형으로 근사하여 사용자에게 보여준다.

이는 디테일은 다소 떨어질 수 있어도 데이터를 크게 압축할 수 있게 해준다.

위와 같이 모든 좌석이 공연장을 둥글게 둘러 쌌을 때에도, 사진과 같이 구역을 나누면 또한 직사각형으로 근사할 수 있게 된다.

최악의 경우는 둥글게 둘러쌌으면서 그 규모가 매우 작을 때다. 이 때에는 구역을 나눠 직사각형으로 근사하기가 힘들어진다.

그러나 그런 경우는 정말 찾아볼 수 없을 정도다.

만약 그런 경우가 있다 하더라도, 구역 당 좌석이 적어서 불편할 순 있어도 결국 구현이 가능한 시스템이다.

좌석 저장 방식:

  1. 좌석 렌더링 방식:
    1. Place에서 오버뷰 SVG와 섹션 리스트를 얻는다.
    2. 오버뷰 SVG, 섹션 각각의 SVG를 이용해 좌석 요약도를 그린다.
    3. 하나의 섹션이 클릭되면, 해당 섹션의 좌석 배열을 따라 좌석을 그린다.
    4. 좌석이 선택되면, 해당 섹션 이름(서버 제공)과 행/열 정보(클라이언트 계산 응답에서 서버가 계산해 넘겨줌)를 나타낸다.
  2. 좌석 예약/취소 방식:
    1. 좌석이 선택되면, 섹션 index, 좌석 index를 포함한 요청을 보낸다.
    2. 서버는 섹션 index를 seats의 1차원 인덱스로, 좌석 index를 seats의 2차원 인덱스로 하여, Event의 seats를 수정한다.
  3. 좌석 현황 업데이트 방식:
    1. 서버가 Event의 seats 배열을 boolean 배열로 변환하여(애초에 빈 칸인 좌석을 제거함. 클라이언트가 이 공백을 추론해야함. 애초에 빈 칸을 포함하여 예약 가능/불가능 여부로 bool값이 설정됨.) SSE를 발행한다.
      • boolean 배열로 굳이 변환하는 이유:
        • 성능적으로 가장 중요한 SSE 브로드캐스트 부분을 최대한 최적화하기 위함.
        • 좌석의 개수가 일반적으로 많기 때문에 이 부분에서 생기는 차이가 유의미하리라 예상함.
    2. 클라이언트는 이미 가지고 있는 좌석 배치 정보를 기반으로, 수신한 seats 배열을 해석해 좌석 현황을 재렌더링한다.
  4. 예약 확정 방식:
    1. 유저가 선택한 섹션 index를 통해 Section의 ‘구역 이름’을 얻는다.
    2. 유저가 선택한 좌석 index를 통해 ‘좌석 이름’(ex: ‘B열 3번’)을 계산한다.
    3. 위 값들로 Reservation 엔티티를 생성하여 저장한다.
  5. 예약 확정 후 취소 방식:
    1. Reservation의 seats 배열이 가진 (섹션 index, 좌석 index) 좌표로 Event의 seats에 접근하여 예약 상태를 변경한다.

추가 개선(v3)

image.png

주요 변경 사항: