Skip to content

OHEUNSOL/TablePick-BackEnd

 
 

Repository files navigation

TablePick-BackEnd

이 레포는 팀 프로젝트로 진행한 식당 예약·결제 플랫폼에서
제가 맡았던 예약·결제 도메인을 중심으로 개인적으로 정리해 둔 버전입니다.
(원본 팀 프로젝트: 링크)

🤝 협업 문서

프로젝트 진행 일정, 와이어프레임, 협업 전략 등은 별도 문서에 정리했습니다.
👉 협업 아카이브 바로가기


🔗 관련 레포지토리


🚀 프로젝트 개요

TablePick은 대규모 트래픽을 처리할 수 있는 레스토랑 예약·결제 플랫폼입니다.
예약 슬롯 관리, 결제 처리, 성능 최적화를 중점적으로 개선했습니다.


🛠 기술 스택

🔹 프론트엔드

React TypeScript TailwindCSS

🔹 백엔드

Java Spring Boot Spring Security MySQL Redis OAuth FCM JWT

🔹 AI & Data

Python FastAPI scikit-learn pandas numpy Selenium

🔹 협업 도구

GitHub Jira Notion Discord


📌 주요 기능

  • 알림(Alarm): 예약 스케줄링과 푸시 알림을 관리하며, 회원별 알림 내역을 제공합니다.
  • 게시판(Board): 게시글 작성, 수정, 삭제 및 태그 관리 기능을 통해 커뮤니티를 운영할 수 있습니다.
  • 회원(Member): 카카오·구글 소셜 로그인을 지원하고, 회원 정보 및 예약·게시글 내역을 조회·관리할 수 있습니다.
  • 예약(Reservation): 사용자는 예약을 생성·취소하고, 가능한 예약 시간을 실시간으로 확인할 수 있습니다.
  • 결제(Payment): 예약 과정과 연동된 결제 처리, 내역 조회, 결제 취소 기능을 제공합니다.
  • 식당(Restaurant): 전체 식당 목록과 키워드·카테고리 기반 검색, 상세 조회 기능을 지원합니다.

📐 아키텍처

image

🗺 ERD

image > 원본 ERD : [ERDCloud 보기](https://www.erdcloud.com/d/pKQZMxpT7NpDe9wn9)

🛠 기술 스택

  • Backend: Java 21, Spring Boot
  • Infra / Data: Kafka, MySQL, Redis, Docker
  • Testing / Observability: k6, Grafana, Prometheus

✅ 개선 사항

1) 대량 데이터 삽입 성능 개선

  • 문제

    • 예약 슬롯은 한 달 기준 약 4,987,200건 생성 필요.

    • 초기 구현(JPA + IDENTITY)은 개별 INSERT 방식이라 대량 삽입 시 병목 발생.
      → 실제 실행 결과: 2,010,952ms (약 33분 31초 소요)

      image
  • 해결

    • JdbcTemplate 기반으로 전환하고 Batch(3000) 적용.
  • 결과

    방식 실행 시간 개선율
    JPA + IDENTITY 2,010,952 ms -
    JdbcTemplate 73,243 ms 약 96.36% 개선
    JdbcTemplate + Batch(3000) 48,092 ms 약 97.61% 개선
    • 추가로 멀티스레드 병렬 처리 / 체크포인트 기반 롤백 설계안을 마련해 대규모 트래픽 대비.
  • 실행 결과 캡처 image image

  • 추가 계획

    • Spring Batch / Quartz로 삽입 스케줄링 최적화.
    • 초대용량 환경에서는 Kafka 기반 비동기 처리 도입 검토.

2) 예약 동시성 & 트랜잭션 범위 최적화

  • 문제

    • 동시 요청 150명, 수용 인원 100명, 스레드풀 32 환경에서
      동일 슬롯에 대해 공유락(S) → 배타락(X) 전환 시 충돌로 데드락 발생.
    • saveAndFlush() 적용으로 데드락은 해소했지만, 예약 수 불일치(정합성) 문제는 남아있었음.

    데드락 에러 로그
    image

    데드락 해소 후에도 남은 정합성 이슈(예약 수 불일치)
    image

    • 해결

    • 락 전략 적용

      • 인기 슬롯: 비관적 락(Pessimistic Lock)
      • 비인기 슬롯: 낙관적 락(Optimistic Lock)

      성능 비교 결과

      방식 실행 시간
      낙관적 락 3071ms
      비관적 락 909ms
      image image

      → 비관적 락이 낙관적 락 대비 3.38배 성능 개선

    1. 데드락 제거

      • 공유락(S Lock)과 배타락(X Lock) 충돌 원인 분석
      • 락 획득 순서 및 범위 재설계로 무한 대기 상태 제거
    2. 트랜잭션 범위 최소화

      • 예약 저장은 트랜잭션 내에서 처리
      • 외부 결제 API 호출은 트랜잭션 밖으로 분리
      image
  • 결과

    • 락 전략:
      • 낙관적 락 실행 시간: 3071ms
      • 비관적 락 실행 시간: 909ms3.38배 개선
    • 트랜잭션 범위 축소:
      • 대기 시간 평균 40% 개선, 최대 50% 개선 (동시요청 20 기준)
  • 장애 대비

    • 결제 API 장애 시 전체 롤백 대신
      3분 주기 보정 스케줄러를 통해 결제 ID 누락을 자동 보정 → 결과적 일관성 확보
  • 추가 계획

    • 락 경합 모니터링을 Grafana 대시보드에 시각화하여 SLA 관점에서 추적
    • 분산 락(Redis 기반) 검토로 DB 락 부담 완화
    • CQRS 패턴을 적용해 조회 부하와 예약/결제 트랜잭션 분리

3) 결제 서비스 분리 & Kafka 기반 비동기화

  • 배경

    • 결제 장애가 예약 흐름 전체로 전파되는 문제가 있어, 관심사 분리(결제 서버 분리)확장성 확보가 필요했습니다.
  • 설계

    • 예약 서비스 ↔ 결제 서비스 분리 배치.
    • 동기 REST 호출 중심 흐름을 Saga(보상 트랜잭션) + Kafka 이벤트로 전환해 결제 지연/장애의 영향 범위를 축소.
    • 핵심 이벤트
      • ReservationCreated → 결제 요청
      • PaymentSucceeded/Failed → 예약 확정/보상(취소) 처리
    • 멱등성 키(reservationId)로 중복 소비 방지, 파티션 키로 순서 보장(동일 예약 단위).

📌 예약/결제 아키텍처 (Saga 패턴)

본 시스템은 예약과 결제가 분리된 구조로, **Saga 패턴(보상 트랜잭션)**을 적용하여 장애 전파를 최소화했습니다.

1) 정상 플로우

예약 요청 → 예약 서비스(DB 저장) → 결제 이벤트 발행 → 결제 서비스 → PG사 승인/취소 처리

image

2) 실패 시 보상 플로우

결제 실패 이벤트 발생 시 → 예약 서비스에서 결제 취소/롤백 처리 → 데이터 정합성 보장

image

📊 결과 (k6 부하 테스트, VU=5000)

🔹 분리 전

  • 처리량(Request Rate): 126.8 r/s
  • 평균 지연시간: 5초
  • GitHub Actions 빌드 시간: 2분 41초
image

🔹 분리 후 (동기 호출)

  • 처리량(Request Rate): 93.2 r/s
  • 평균 지연시간: 9초
  • GitHub Actions 빌드 시간: 1분 46초
image

🔹 분리 후 (Kafka 비동기)

  • 처리량(Request Rate): 285.39 r/s (약 2.9배 증가)
  • 평균 지연시간: 1~2초
image

🔹 최종 비교

image

🚀 CI/CD 배포 효율 개선 (결제 서버 분리 효과)

  • 배경

    • 기존 단일 서버 구조에서는 예약/결제 코드가 한 레포에 묶여 있어, 결제 로직 수정 시 전체 서버를 다시 빌드/배포해야 했음.
    • 결제 서버를 별도 마이크로서비스로 분리하면서 독립 배포 가능.
  • 결과 (GitHub Actions 빌드 시간 비교)

    • 분리 전: 전체 서버 빌드/배포 2분 41초
    • 분리 후: 결제 서버만 배포 → 1분 46초
image

결제 서버 분리를 통해 배포 속도가 약 35% 개선되었으며, 운영 시 장애 영향 범위도 축소.

  • 안정성

    • 재시도(Backoff) + DLQ: 일시 장애 시 자동 재처리, 영구 실패는 DLQ로 격리.
    • Outbox 패턴(계획): DB 트랜잭션과 이벤트 발행을 분리·안정화(이벤트 유실/중복/순서 보장).
  • 운영 포인트

    • Topic/Partition: payments 토픽, 예약ID 기반 파티셔닝(동일 예약 순서 보장).
    • Idempotency: reservationId + 상태머신(READY→PAID/FAILED)로 중복 처리 차단.
    • 모니터링: 소비 지연(consumer lag), 재시도/실패율, DLQ 수치 대시보드화.
  • 추가/고도화 계획

    • Outbox를 트랜잭션 로그 테이블 기반으로 구현 + Outbox Relayer 배치.
    • Exactly-once 흐름 강화: 소비측 멱등키 캐시/테이블, Producer idempotence 설정.
    • 보상 트랜잭션 시나리오 문서화(부분 실패 케이스별 롤백/보상 단계).
    • 부하 프로파일 확대: VU/러닝타임/에러율 스윗스팟 산출 후 오토스케일 기준 반영.

🧪 실험 환경 & 테스트 설정

  • 클라우드: AWS (단일 VPC, 동일 AZ)
  • 애플리케이션
    • 예약 서비스: EC2 t3.medium (2 vCPU, 4GiB)
    • 결제 서비스: EC2 t3.medium (2 vCPU, 4GiB)
  • 데이터베이스
    • Amazon RDS for MySQL – db.t3.large (2 vCPU, 4GiB)
  • 메시징
    • Apache Kafka 클러스터 (단일 브로커) – EC2 (동일 VPC, 내부 통신)
  • 오토스케일링: 비활성 (고정 인스턴스, 테스트 간 동일 조건 유지)
  • k6 부하 테스트
    • VU(가상사용자) = 5000
    • 요청 패턴: 예약→결제 플로우 단일 엔드포인트 중심
    • 각 시나리오 사전 워밍업 30s 후 측정(콜드 스타트 영향 최소화)

📝 남은 작업 (TODO)

  • DB 인덱스 최적화: 예약 슬롯/식당 데이터 조회 성능 개선
  • Outbox 패턴 안정화: 이벤트 발행의 신뢰성 보장 (트랜잭션 경계 명확화)
  • 데이터 정합성 보강: 예약 취소/결제 취소 시 트랜잭션 처리
  • 에러 핸들링 강화: 외부 결제 API 장애 상황 시 재시도 & 보상 처리

🎥 시연 영상

https://drive.google.com/file/d/1ZoBAgl4vPlDY5-KWDxwHWnN-WZnCq-e9/view?usp=sharing

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Java 96.7%
  • JavaScript 3.3%