글 검색

공개된 글의 제목과 본문을 검색합니다.

    닫기 Esc

    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. 예약의 라이프사이클#

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

    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는 모든 노드의 트랜잭션을 하나로, 사가는 각 단계별로 분리한 개념
    전체 글 둘러보기