////
Search

21장 - 호텔 예약 시스템

생성일
2024/08/18 12:13
태그
Interview

1. 요구사항 정리

1.1. 기능적 요구사항

5,000개의 호텔에 100만 개의 객실을 갖춘 호텔 체인을 위한 웹사이트 구축
호텔 예약시 모든 대금을 지급한다고 가정
사용자는 객실 예약을 취소할 수 있음
객실 취소를 예상하여 10% 초과 예약이 가능하도록 함
객실 가격이 여유에 따라 유동적으로 변경될 수 있어야 함

1.2. 비기능적 요구사항

높은 수준의 동시성 지원 = 성수기나 이벤트 기간일 때 고객이 많이 몰릴 수 있음
적절한 지연 시간 = 응답시간이 빠르면 이상적이겠으나 요청에 몇 초 지연은 괜찮다.

1.3. 규모 추정

5,000개의 호텔, 100만 개의 객실, 평균적으로 70%가 사용 중, 평균 3일을 투숙
일일 예약 건수 = 1백만 * 0.7 / 3 = 약 240,000
초당 예약 건수 = 240,000 / 하루에 10^5초 = 약 3
즉 TPS는 그렇게 높지 않다.

2. 청사진 그리기

2.1. 예약의 라이프사이클

flowchart TD
	결제대기 --> 예약취소
	결제대기 --> 결제완료
	결제완료 --> 환불완료
	결제대기 --> 승인실패
Mermaid
복사

2.2. MSA 도입

MSA는 각 도메인에 집중된 단위의 단독 프로덕트로 분리한 형식의 아키텍쳐다
공개 API 게이트웨이를 통해서 사용자는 각 서비스를 사용할 수 있다.
처리율 제한장치나 인증 등을 지원하는 완전 관리형 서비스다.
내부 API는 VPN이나 내부 소프트웨어를 통해서만 접속 가능하다.
서비스간 통신은 gRPC와 같은 고성능 원격 프로시저 호출 프레임 워크를 사용하곤 한다.

3. 설계 시작

고가용성을 위해서 여러 지역에 데이터베이스를 분산시켜야 한다.
해당 도서에서는 2년 내 가용 객실 데이터를 배치로 넣어두고 사용하는 걸로 설계했다.
하나의 ROW값에 예약 받을 수 있는 객실 수와 현재 예약수를 저장해둔다.
그리고 예약 받을 수 있는 수에 10%을 증가시켜 예약 가능 수로 책정한다.

3.1. 동시성

만약 같은 사용자가 예약을 여러번 누른다면?
클라이언트 측에서 예약 버튼 클릭시 버튼을 비활성화 시켜서 예방 할 수 있다.
자바스크립트를 아는 사용자면 우회 가능하다
멱등성을 갖추도록 예약키를 생성해서 예약시 함께 첨부하도록 한다.
같은 키로 예약할 시 동시에 여러번 클릭해도 처음에만 예약된다.
여러 사용자가 동시에 잔여객실이 1밖에 없는 같은 객실을 예약하려 한다면?
레이스컨디션에 의해서 읽는 시점에 따라 둘 다 객실이 하나가 남았다고 뜰 수 있고 이 경우 오버부킹 될 수 있다.
이런 문제를 해결하려면 해당 Row에 Lock을 걸어야한다.

3.1.1. 비관적 Lock

가장 기본적이며 간편한 락기법이며 하나의 트랜잭션이 만들어지면 작업이 끝날때까지 해당 ROW를 갱신할 수 없는 상태로 만든다.
구현이 쉽고, 데이터 경합이 심할때 이용하면 좋다.
여러 레코드에 락을 건다면 교착상태가 발생할 수 있고, 성능에 영향을 미칠 수 있다.

3.1.2. 낙관적 Lock

낙관적 락은 ROW에 버전이나 타임스탬프를 남겨서 같은 자원 갱신을 막는 방안이다.
일반적으로 버전을 더 나은 방법으로 여긴다.
방법은 간단한데 ROW갱신 시 버전도 같이 업데이트 하는데 버전이 같은걸로 업데이트 하려고 할시 후속 쿼리는 오류처리하도록 하는것이다.
일반적으로 비관적락보다 빠르고 데이터베이스 자원에 락을 거는게 아니기 때문에 교착상태에 빠질걱정이 없다.
그렇지만 경쟁이 치열한 상황이라면 성능이 떨어질 수 있다.
매 갱신마다 유효성 검사를 해야하기 때문이다.

3.1.3. 데이터베이스 제약조건

데이터베이스 갱신 시 자체적으로 연산 후 등록하도록 하는 방법이다.
구현이 쉬운 장점이 있다.
경쟁이 심하면 연산 수가 증가해 성능이 떨어질 수 있다.

3.2. 캐시

호텔 캐시는 현재와 미래의 데이터만 중요하다.
때문에 TTL, LRU를 통한 캐시 정책이 적절하다.
일반적으로 잔여 객실 수를 캐시로 보여주고 이후 실제 객실은 DB로 질의하도록 한다.

3.3. 서버간 데이터 일관성

MSA에서는 각자 독립적인 데이터베이스를 가지기 때문에 데이터 일관성 문제를 낳는다.
해결 방법의 대표적 예시
2단계 커밋 = 여러 노드에 걸친 원자적 트랜잭션 실행을 보증하는 프로토콜
단, 블록킹 프로토콜이여서 어느 한 노드에 장애가 발생하면 복구될 때까지 중단된다.
성능이 뛰어난 프로토콜은 아니다.
사가 패턴
각각의 트랜잭션은 완료되면 다음 트랜잭션을 시작한다.
실행 중 어느 트랜잭션이 실패하면 순차적으로 이전 트랜잭션을 되돌린다.
2PC는 모든 노드의 트랜잭션을 하나로, 사가는 각 단계별로 분리한 개념