Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,70 @@
# auction-na0th
auction 개인 프로젝트
## 경매 서비스 플랫폼

# 🧭 실시간 경매 API

## 🛠 사용 기술 스택

- Java/Spring Boot
- JPA/QueryDSL
- MySQL

## 경험한 기술
- AWS EC2
- Docker
- Github Actions / Jenkins

팀 프로젝트로 진행했던 경매 서비스에서 맡아보지 못했던 입찰, 경매 스케쥴링, <BR> 인덱스 및 쿼리 최적화, CI/CD를 직접 경험해보고 싶어 추가로 진행한 프로젝트입니다.

- **프로젝트 기간**: 2024.12 ~ 2025.02
- **Back-End**: 최건 (na0th)

## ✨ 주요 구현

| 기능 | 설명 |
|------|------|
| 경매 입찰 | 실시간·양방향 통신을 위해 WebSocket/STOMP의 Pub/Sub 구조 도입하여 입찰 구현|
| 인덱스 및 쿼리 최적화 | WHERE 조건과 JOIN 조건을 고려한 복합 인덱스 적용으로 성능 개선 (1.3초 → 0.07초)|
| 경매 스케쥴링 | JobRunr 라이브러리를 활용하여 경매 시작/종료 시점에 맞춰 자동 실행|
| 동시성 제어 |트랜잭션 버전 기반 낙관적 락과 재시도 로직으로 동시 입찰 충돌 방지|




## 🔍 문제 해결 사례

### 1️⃣ 인덱스 및 쿼리 최적화
- **문제 :** OFFSET 기반 페이징 조회 시, DB 조회 및 응답 시간이 1초 이상으로 측정되었습니다. 체감 속도 저하가 뚜렷하여, UX에 매우 부정적인 영향을 줄 수 있다고 판단했습니다.

- **원인 :** 실행 계획을 보니, WHERE 조건과 JOIN 관련 인덱스가 없어 테이블 풀 스캔이 일어났고, 페이징 연산(OFFSET/LIMIT)이 JOIN 이후에 일어나서 생긴 OFFSET만큼의 불필요한 JOIN 연산이 병목 원인이었습니다.
- **해결 :** 복합 인덱스를 추가하고, 페이징 대상 ID만 서브쿼리로 먼저 조회한 뒤 필요한 데이터에만 JOIN을 수행하도록 쿼리를 개선했습니다.
- **결과 :** OFFSET 4000 기준 응답 시간이 기존 1.3초에서 0.07초로 크게 단축되었습니다.

🔗 [관련 기술 블로그 글](https://velog.io/@na0th/%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0)

### 2️⃣ 실시간 입찰 구현
- **배경 :** 입찰 간 몰입감을 줘, 더 많은 사용자 참여를 유도하기 위해서는 입찰 결과를 사용자에게 실시간으로 반영해야 했습니다.
- **기술 선택 :** 실시간 양방향 통신을 위해 WebSocket과 STOMP 기반의 Pub/Sub 구조를 도입했습니다.
- **근거 :**
- HTTP Polling는 클라이언트가 주기적으로 요청을 보내는 구조로 서버의 상태 변화를 즉각 반영하기는 어렵고, 불필요한 네트워크 오버헤드가 발생하기 때문에 선택하지 않았습니다.
- HTTP Long Polling 방식도 조금은 개선되었으나, 요청-응답 구조라는 한계가 있어, 서버가 먼저 데이터를 푸시하지 못하기 때문에 선택하지 않았습니다.
- WebSocket 방식은 최초에 TCP 연결을 맺고 이를 지속적으로 유지함으로써, 클라이언트가 별도의 요청 없이도 서버로부터 실시간 메시지를 수신할 수 있습니다.
이로 인해 입찰을 하지 않은 클라이언트도 입찰 결과를 실시간으로 전달받아 웹 UI를 갱신할 수 있기 때문에 WebSocket 방식을 선택했습니다.


- **결과 :** 실시간으로 입찰을 처리하고, 서버에서 구독한 클라이언트에게 데이터 푸시해서 웹 UI 갱신하여 실시간 입찰 구현
<BR>
🔗[입찰 구현 구조도]<BR>

## 🔗 프로젝트 관련 링크

- **API 문서 :** [TODO: Swagger]


## 📝 회고

> 경매, 팀 프로젝트 하는 동안 제가 맡은 도메인을 제외하면 기술적으로 어떻게 돌아가는지를 알고 있다는 느낌이 적었어서 안 해봤던 부분 혼자서 공부하면서 만들어 보고 싶어 진행했습니다.
<BR><BR>
> 개인적으로 해보고 싶었던 것들 위주로 해보려고 했는데, 그러다보니 서비스라 볼 수 없는는 불완전하고 파편화된 구현을 한 것 같습니니다. 그래도 많은 기술들을 접해봤고, 심도 있게 공부해서 적용한 부분도 있어 좋았습니다.
<BR><BR>
> 평소에 어려울 거라 생각해서 미뤘었던 인덱스/쿼리 성능 최적화를 깊이 있게 공부하여 적용했고, 도커를 통한 CD 파이프라인 구성 <BR>
> 어렵다고 생각해도 막상 하고자 하면 어떻게든 할 수 있다고 느껴, 자신감을 얻었습니다.