From 672a6d77d560ebb5be079997e5d1b4d44f5e2935 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B1=B4=20=EC=B4=88=EC=9D=B4?=
<105775683+na0th@users.noreply.github.com>
Date: Sat, 17 May 2025 16:11:44 +0900
Subject: [PATCH] =?UTF-8?q?README=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
구현 기능, 트러블 슈팅 경험, 회고 추가
---
README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 70 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 67af72f..c0b73bc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,70 @@
-# auction-na0th
- auction 개인 프로젝트
+## 경매 서비스 플랫폼
+
+# 🧭 실시간 경매 API
+
+## 🛠 사용 기술 스택
+
+- Java/Spring Boot
+- JPA/QueryDSL
+- MySQL
+
+## 경험한 기술
+- AWS EC2
+- Docker
+- Github Actions / Jenkins
+
+팀 프로젝트로 진행했던 경매 서비스에서 맡아보지 못했던 입찰, 경매 스케쥴링,
인덱스 및 쿼리 최적화, 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 갱신하여 실시간 입찰 구현
+
+🔗[입찰 구현 구조도]
+
+## 🔗 프로젝트 관련 링크
+
+- **API 문서 :** [TODO: Swagger]
+
+
+## 📝 회고
+
+> 경매, 팀 프로젝트 하는 동안 제가 맡은 도메인을 제외하면 기술적으로 어떻게 돌아가는지를 알고 있다는 느낌이 적었어서 안 해봤던 부분 혼자서 공부하면서 만들어 보고 싶어 진행했습니다.
+
+> 개인적으로 해보고 싶었던 것들 위주로 해보려고 했는데, 그러다보니 서비스라 볼 수 없는는 불완전하고 파편화된 구현을 한 것 같습니니다. 그래도 많은 기술들을 접해봤고, 심도 있게 공부해서 적용한 부분도 있어 좋았습니다.
+
+> 평소에 어려울 거라 생각해서 미뤘었던 인덱스/쿼리 성능 최적화를 깊이 있게 공부하여 적용했고, 도커를 통한 CD 파이프라인 구성
+> 어렵다고 생각해도 막상 하고자 하면 어떻게든 할 수 있다고 느껴, 자신감을 얻었습니다.