Skip to content

vivalahm/hhplus_3week_ticketing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

콘서트 티케팅 시스템

Milestone

image

FLowChart

image

Sequence Diagram

image

image

image

API 명세서

1. 유저 토큰 발급 API

  • Endpoint

    • URL: /api/token
    • Method: POST
    • 설명: 대기열을 위한 유저 토큰 발급 요청
  • Request

    • Body:

      항목 Type 설명 비고
      userId Long 유저 ID
  • Response

    • HTTP Status Codes:

      • 200 OK: 성공
      • 400 Bad Request: 잘못된 요청
      • 500 Internal Server Error: 서버 오류
    • Body:

      항목 Type 설명 비고
      result String 결과 코드 (200 : 성공 / 그 외 : 실패)
      message String 결과 메시지
      data Object 토큰 데이터
    • data 정보 파라미터

      항목 Type 설명 비고
      token String 대기열 토큰
      queuePosition Integer 대기열 위치
      expiresAt String 토큰 만료 시간
    • 응답 예시

      {
          "result": "200",
          "message": "Success",
          "data": {
              "token": "randomUUID",
              "queuePosition": 1,
              "expiresAt": "2024-07-04T12:00:00"
          }
      }
  • Error

    • 400 Bad Request: 필수 파라미터 누락 또는 잘못된 데이터 형식

      • 응답 예시

        {
            "result": "400",
            "message": "Missing or invalid userId"
        }
    • 500 Internal Server Error: 토큰 발급 중 서버 오류

      • 응답 예시

        {
            "result": "500",
            "message": "Internal server error"
        }
  • Authorization: 없음

2. 예약 가능 날짜 / 좌석 API

  • 예약 가능 날짜 조회

    • Endpoint

      • URL: /api/{concertId}/available-dates
      • Method: GET
      • 설명: 예약 가능한 날짜를 조회합니다.
    • Request

      • Query Parameters:

        항목 Type 설명 비고
        token String 유저 토큰
        concertId Long 콘서트Id
    • Response

      • HTTP Status Codes:

        • 200 OK: 성공
        • 401 Unauthorized: 인증 실패
        • 500 Internal Server Error: 서버 오류
      • Body:

        항목 Type 설명 비고
        concertOptions List<Object> 예약 가능 콘서트 옵션 리스트
      • concertOptions 정보 파라미터

        항목 Type 설명 비고
        concertOptionId Long 콘서트 옵션 ID
        concertDate String 콘서트 날짜
      • 응답 예시

        {
            "concertOptions": [
                {
                    "concertOptionId": 1,
                    "concertDate": "2024-07-04"
                },
                {
                    "concertOptionId": 2,
                    "concertDate": "2024-07-05"
                }
            ]
        }
    • Error

      • 401 Unauthorized: 유효하지 않은 토큰

        • 응답 예시

          {
              "result": "401",
              "message": "Invalid or expired token"
          }
      • 500 Internal Server Error: 서버 오류

        • 응답 예시

          {
              "result": "500",
              "message": "Internal server error"
          }
    • Authorization: 유저 토큰 필요

      • Authorization Header:

        Authorization: Bearer randomUUID
        
  • 예약 가능 좌석 조회

    • Endpoint

      • URL: /api/{concertOptionId}/available-seats
      • Method: GET
      • 설명: 특정 날짜에 예약 가능한 좌석을 조회합니다.
    • Request

      • Query Parameters:

        항목 Type 설명 비고
        token String 유저 토큰
        concertOptionId Long 콘서트 옵션 ID
    • Response

      • HTTP Status Codes:

        • 200 OK: 성공
        • 401 Unauthorized: 인증 실패
        • 500 Internal Server Error: 서버 오류
      • Body:

        항목 Type 설명 비고
        seats List<Object> 예약 가능 좌석 리스트
      • seats 정보 파라미터

        항목 Type 설명 비고
        seatId Long 좌석 ID
        seatNumber String 좌석 번호
        status String 좌석 상태
      • 응답 예시

        {
            "seats": [
                {
                    "seatId": 1,
                    "seatNumber": "A1",
                    "status": "열림"
                },
                {
                    "seatId": 2,
                    "seatNumber": "A2",
                    "status": "열림"
                }
            ]
        }
    • Error

      • 401 Unauthorized: 유효하지 않은 토큰

        • 응답 예시

          {
              "result": "401",
              "message": "Invalid or expired token"
          }
      • 500 Internal Server Error: 서버 오류

        • 응답 예시

          {
              "result": "500",
              "message": "Internal server error"
          }
    • Authorization: 유저 토큰 필요

      • Authorization Header:

        Authorization: Bearer randomUUID
        

3. 좌석 예약 요청 API

  • Endpoint

    • URL: /api/reserve
    • Method: POST
    • 설명: 좌석 예약 요청
  • Request

    • Body:

      항목 Type 설명 비고
      token String 유저 토큰
      concertOptionId Long 콘서트 옵션 ID
      seatId Long 좌석 ID
      userId Long 유저 ID
  • Response

    • HTTP Status Codes:

      • 200 OK: 성공
      • 401 Unauthorized: 인증 실패
      • 400 Bad Request: 잘못된 요청
      • 500 Internal Server Error: 서버 오류
    • Body:

      항목 Type 설명 비고
      result String 결과 코드 (200 : 성공 / 그 외 : 실패)
      message String 결과 메시지
      data Object 예약 결과 데이터
    • data 정보 파라미터

      항목 Type 설명 비고
      reservationId Long 예약 ID
    • 응답 예시

      {
          "result": "200",
          "message": "Success",
          "data": {
              "reservationId": 123
          }
      }
  • Error

    • 401 Unauthorized: 유효하지 않은 토큰

      • 응답 예시

        {
            "result": "401",
            "message": "Invalid or expired token"
        }
    • 400 Bad Request: 필수 파라미터 누락 또는 잘못된 데이터 형식

      • 응답 예시

        {
            "result": "400",
            "message": "Missing or invalid parameters"
        }
    • 500 Internal Server Error: 서버 오류

      • 응답 예시
    	{
          "result": "500",
          "message": "Internal server error"
      }
    • Authorization: 유저 토큰 필요

      • Authorization Header:

        Authorization: Bearer randomUUID
        

    4. 잔액 충전 / 조회 API

    • 잔액 충전

      • Endpoint

        • URL: /api/balance/charge
        • Method: PATCH
        • 설명: 유저의 잔액을 충전합니다.
      • Request

        • Body:

          항목 Type 설명 비고
          userId Long 유저 ID
          amount Double 충전 금액
      • Response

        • HTTP Status Codes:

          • 200 OK: 성공
          • 400 Bad Request: 잘못된 요청
          • 500 Internal Server Error: 서버 오류
        • Body:

          항목 Type 설명 비고
          balance Double 현재 잔액
        • 응답 예시

          {
              "balance": 5000.00
          }
      • Error

        • 400 Bad Request: 필수 파라미터 누락 또는 잘못된 데이터 형식

          • 응답 예시

            {
                "result": "400",
                "message": "Missing or invalid parameters"
            }
        • 500 Internal Server Error: 서버 오류

          • 응답 예시

            {
                "result": "500",
                "message": "Internal server error"
            }
      • Authorization: 없음

    • 잔액 조회

      • Endpoint

        • URL: /api/balance
        • Method: GET
        • 설명: 유저의 현재 잔액을 조회합니다.
      • Request

        • Query Parameters:

          항목 Type 설명 비고
          userId Long 유저 ID
      • Response

        • HTTP Status Codes:

          • 200 OK: 성공
          • 400 Bad Request: 잘못된 요청
          • 500 Internal Server Error: 서버 오류
        • Body:

          항목 Type 설명 비고
          balance Double 현재 잔액
        • 응답 예시

          {
              "balance": 5000.00
          }
      • Error

        • 400 Bad Request: 필수 파라미터 누락 또는 잘못된 데이터 형식

          • 응답 예시

            {
                "result": "400",
                "message": "Missing or invalid parameters"
            }
        • 500 Internal Server Error: 서버 오류

          • 응답 예시

            {
                "result": "500",
                "message": "Internal server error"
            }
      • Authorization: 없음

    5. 결제 API

    • Endpoint

      • URL: /api/pay
      • Method: POST
      • 설명: 결제 요청
    • Request

      • Body:

        항목 Type 설명 비고
        token String 유저 토큰
        reservationId Long 예약 ID
        amount Double 결제 금액
    • Response

      • HTTP Status Codes:

        • 200 OK: 성공
        • 401 Unauthorized: 인증 실패
        • 400 Bad Request: 잘못된 요청
        • 500 Internal Server Error: 서버 오류
      • Body:

        항목 Type 설명 비고
        result String 결과 코드 (200 : 성공 / 그 외 : 실패)
        message String 결과 메시지
        data Object 결제 결과 데이터
      • data 정보 파라미터

        항목 Type 설명 비고
        paymentId Long 결제 ID
      • 응답 예시

        {
            "result": "200",
            "message": "Success",
            "data": {
                "paymentId": 456
            }
        }
    • Error

      • 401 Unauthorized: 유효하지 않은 토큰

        • 응답 예시

          {
              "result": "401",
              "message": "Invalid or expired token"
          }
      • 400 Bad Request: 필수 파라미터 누락 또는 잘못된 데이터 형식

        • 응답 예시

          {
              "result": "400",
              "message": "Missing or invalid parameters"
          }
      • 500 Internal Server Error: 서버 오류

        • 응답 예시

          {
              "result": "500",
              "message": "Internal server error"
          }
    • Authorization: 유저 토큰 필요

      • Authorization Header:

        Authorization: Bearer randomUUID
        

ERD

image

에러 로깅 처리

image

동시성 제어 방법에 따른 성능 및 사용성 비교 보고서

테스트 환경

  • 서버: 로컬 머신
  • Redis: Docker 컨테이너로 실행된 Redis 인스턴스
  • Spring Boot: 버전 3.3.1
  • Java: 버전 17

테스트 결과 요약

1. 성능적인 부분 (초)

비관적 락 (Pessimistic Locking)

  • 성능 결과:
    • 락 획득 및 작업 완료 시간: 약 100ms - 200ms
    • 데이터베이스 락을 사용하기 때문에 성능 저하가 발생할 수 있음
    • 전체 성능: 느림

낙관적 락 (Optimistic Locking)

  • 성능 결과:
    • 락 충돌이 없을 때: 약 20ms - 50ms
    • 락 충돌이 발생할 때: 약 50ms - 100ms (재시도 포함)
    • 전체 성능: 보통

Redis 분산 락 (Distributed Lock)

  • 성능 결과:
    • 락 획득 및 작업 완료 시간: 약 25ms - 30ms
    • 인메모리 데이터베이스인 Redis를 사용하여 빠른 성능 제공
    • 전체 성능: 빠름

2. 결과에 정합성

비관적 락 (Pessimistic Locking)

  • 정합성: 매우 높음
    • 데이터베이스 레벨에서 락을 사용하여 모든 트랜잭션이 순차적으로 실행됨
    • 충돌이 발생하지 않음

낙관적 락 (Optimistic Locking)

  • 정합성: 높음
    • 데이터베이스에서 버전 필드를 사용하여 충돌을 감지하고, 충돌 시 재시도 로직으로 처리
    • 일부 트랜잭션이 실패할 수 있으나, 원하는 결과를 보장

Redis 분산 락 (Distributed Lock)

  • 정합성: 매우 높음
    • 분산 환경에서도 일관성을 유지하며, 하나의 트랜잭션만 성공적으로 실행됨
    • 락을 획득하지 못한 트랜잭션은 실패

3. Deadlock 이슈 발생 여부 및 처리 방법

비관적 락 (Pessimistic Locking)

  • Deadlock 발생 여부: 발생 가능
    • 여러 트랜잭션이 서로를 기다리면서 데드락 발생 가능성 존재
  • 처리 방법:
    • 타임아웃 설정 및 재시도 로직 추가
    • 데드락 발생 시 트랜잭션 롤백 및 재시도

낙관적 락 (Optimistic Locking)

  • Deadlock 발생 여부: 발생하지 않음
    • 충돌이 발생할 경우 예외를 발생시키고, 재시도 로직을 통해 처리
  • 처리 방법:
    • 충돌 시 예외 처리 및 재시도 로직

Redis 분산 락 (Distributed Lock)

  • Deadlock 발생 여부: 발생하지 않음
    • 락 획득에 타임아웃을 설정하여 데드락 발생을 방지
  • 처리 방법:
    • 락 획득 실패 시 예외 처리 및 재시도 로직

4. 사용 편의성

비관적 락 (Pessimistic Locking)

  • 사용 편의성: 낮음
    • 데이터베이스 레벨에서 락을 관리해야 하므로 설정 및 유지보수가 복잡
    • 데드락 방지 및 타임아웃 설정 필요

낙관적 락 (Optimistic Locking)

  • 사용 편의성: 높음
    • 간단한 설정으로 사용할 수 있으며, 충돌 시 재시도 로직만 추가하면 됨
    • @Version 필드만 추가하면 구현 가능

Redis 분산 락 (Distributed Lock)

  • 사용 편의성: 보통
    • Redis 설정 및 관리 필요
    • 락 획득 및 해제를 위한 로직이 추가로 필요하지만, 코드 구현은 간단

종합 비교표

비교 항목 비관적 락 낙관적 락 Redis 분산 락
성능 느림 보통 빠름
정합성 매우 높음 높음 매우 높음
Deadlock 발생 여부 발생 가능 발생하지 않음 발생하지 않음
Deadlock 처리 방법 타임아웃 설정 및 재시도 로직 충돌 시 예외 처리 및 재시도 로직 타임아웃 설정 및 재시도 로직
사용 편의성 낮음 높음 보통

결론

  • Redis 분산 락은 특히 분산 시스템에서의 동시성 제어와 확장성 측면에서 매우 강력한 도구로, 데이터베이스의 비관적 락이나 낙관적 락보다 더 유연하고 성능이 뛰어날 수 있음. 사용 편의성 측면에서는 낙관적 락이 가장 간단하며, 비관적 락은 설정과 관리가 복잡하지만 일관성을 강하게 보장.
  • 비관적 락은 데이터 충돌이 빈번한 환경에서 일관성을 보장할 수 있지만, 성능 저하와 Deadlock 발생 가능성 때문에 주의가 필요
  • 낙관적 락은 데이터 충돌이 드문 환경에서 성능이 뛰어나며, Deadlock 발생 가능성이 낮다.
  • Redis 분산 락은 성능과 확장성 측면에서 매우 우수하며, 분산 환경에서 락을 구현하는 데 적합.

테스트 결과

  • 포인트 충전 및 사용: 비관적 락을 사용하여 데이터 정합성을 보장하면서도 성능 저하가 발생할 수 있다.
  • 나머지 트랜잭션: 낙관적 락을 사용하여 높은 성능을 유지하면서도 데이터 정합성을 보장할 수 있다.
  • 전체 트랜잭션 성능: Redis 분산 락을 사용하여 빠른 성능과 높은 정합성을 유지할 수 있다.

세부 테스트 결과

비관적 락 테스트

  1. 포인트 충전 유즈케이스
  • 비관적 락 선택 이유: 한 유저가 포인트를 여러번 충전할때 한번의 트랜잭션이 처리가 끝난후 처리되는게 맞다고 판단하여 비관적 락으로 처리

  • 최종 사용자 포인트: 1000.0

  • 총 실행 시간: 194ms

  • 평균 실행 시간: 19.4ms

image

  1. 포인트 사용 유즈케이스
  • 최종 사용자 포인트: 9000.0
  • 총 실행 시간: 222ms
  • 평균 실행 시간: 22.2ms

image

낙관적 락 테스트

  1. 좌석 예약 유즈 케이스
  • 낙관적 락 선택 이유: 좌석에 대해서 한명만 성공하면 그 이후로 대기할 필요 없기 때문에 낙관적 락을 통해 뒤에 신청한 사용자는 에러를 띄워 주도록 처리

  • 성공한 예약 수: 1

  • 실패한 예약 수: 9

  • 총 실행 시간: 329ms

  • 평균 실행 시간: 32.9ms

image

  1. 결제 유즈케이스
  • 낙관적 락 선택 이유: 하나의 예약에 대한 결제이면서 본인의 예약을 결제하기 때문에 충돌이 적을 것으로 판단 결제 성공 건에 대해서만 처리하고 나머지는 충돌이 발생하면 에러로 띄워 주게 처리

  • 성공한 결제 수: 1

  • 실패한 결제 수: 9

  • 총 실행 시간: 609ms

    평균 실행 시간: 60.9ms

image

About

콘서트 예약 시스템

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published