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
251 changes: 123 additions & 128 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,128 +1,123 @@
# ๐ŸŒฑ UMC 7th FarmON BackEnd

## ๐ŸŒพ Introduce
![Image](https://github.com/user-attachments/assets/95c2519f-7e02-4cec-83e2-6064737ba3e9)
**๋†์—…์˜ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ** **FarmON**์€ UMC 7๊ธฐ์—์„œ ์ง„ํ–‰๋œ ํ”„๋กœ์ ํŠธ ๋ฐ ๋†์—…์˜ ํ˜์‹ ์„ ์ด๋„๋Š” ๋””์ง€ํ„ธ ์†”๋ฃจ์…˜์œผ๋กœ, <br>
**๋””์ง€ํ„ธ ์ปค๋ฎค๋‹ˆํ‹ฐ**๋ฅผ ํ†ตํ•ด ์†Œ๊ทœ๋ชจ ์˜์„ธ๋†์—…์˜ **๊ณต๋™๋†์—…์„ ํ™œ์„ฑํ™”**ํ•˜๊ณ , ํ”Œ๋žซํผ์„ ํ™œ์šฉํ•˜์—ฌ **์ „๊ตญ์˜ ๋†์—… ์ „๋ฌธ๊ฐ€๋ฅผ ์—ฐ๊ฒฐ**ํ•˜๋ฉฐ, **๋†์—… ๋ฐ์ดํ„ฐ**๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ **์ฒด๊ณ„์ ์ธ ๋†์—… ์„œ๋น„์Šค**๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

&nbsp;
## ๐Ÿ”ง Tech Stack
<p>
<img src="https://img.shields.io/badge/SpringBoot-6DB33F?style=for-the-badge&logo=springboot&logoColor=white">
<img src="https://img.shields.io/badge/Java-007396?style=for-the-badge&logo=openjdk&logoColor=white">
<img src="https://img.shields.io/badge/MySQL-4479A1?style=for-the-badge&logo=mysql&logoColor=white">
<img src="https://img.shields.io/badge/Redis-DC382D?style=for-the-badge&logo=redis&logoColor=white">
<img src="https://img.shields.io/badge/JWT-000000?style=for-the-badge&logo=jsonwebtokens&logoColor=white">
<img src="https://img.shields.io/badge/STOMP-6E4C13?style=for-the-badge&logo=apachekafka&logoColor=white">
<img src="https://img.shields.io/badge/RabbitMQ-FF6600?style=for-the-badge&logo=rabbitmq&logoColor=white">
</p>

<p>
<img src="https://img.shields.io/badge/Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white">
<img src="https://img.shields.io/badge/Nginx-009639?style=for-the-badge&logo=nginx&logoColor=white">
<img src="https://img.shields.io/badge/AWS-232F3E?style=for-the-badge&logo=amazonaws&logoColor=white">
<img src="https://img.shields.io/badge/github-181717?style=for-the-badge&logo=github&logoColor=white">
<img src="https://img.shields.io/badge/GitHub_Actions-2088FF?style=for-the-badge&logo=githubactions&logoColor=white">
<img src="https://img.shields.io/badge/Swagger-85EA2D?style=for-the-badge&logo=swagger&logoColor=white">
</p>

&nbsp;
## โœจ Main Feature
![Image](https://github.com/user-attachments/assets/0e433d31-6ec9-40b4-a366-5ca014dcb1ee)

![Image](https://github.com/user-attachments/assets/294d445a-4d2a-4ffb-a95d-2c7aa1b66440)

![Image](https://github.com/user-attachments/assets/d7390577-bd6b-4358-b273-fcb0b344febb)

![Image](https://github.com/user-attachments/assets/c5a11562-41f7-4a39-ac73-72c05ed5a046)

![Image](https://github.com/user-attachments/assets/141ed065-8cc9-4514-9791-dbc9b4b45836)

![Image](https://github.com/user-attachments/assets/6ccf7111-461e-412e-abce-06362a5780ae)

![Image](https://github.com/user-attachments/assets/78d15f3f-728b-41db-b7c6-d2422a81bfec)

![Image](https://github.com/user-attachments/assets/8bf1ba58-6f22-4ef8-95fc-6326b6177220)

![Image](https://github.com/user-attachments/assets/71f7422f-86c1-49d4-bb4b-58bc2209b4c5)

![Image](https://github.com/user-attachments/assets/56db86f1-55c8-43c7-9f9d-256bea93f440)

![Image](https://github.com/user-attachments/assets/d0772f82-fee4-473d-8592-c15d7261f398)

&nbsp;
## ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป Backend Developers

<table>
<tr height="200px">
<td align="center" width="200px">
<a href="https://github.com/LEEYOENN">
<img height="150px" width="150px" src="https://avatars.githubusercontent.com/LEEYOENN"/>
</a>
<br />
<a href="https://github.com/LEEYOENN">๋ฐ์ด/์ด์—ฐ</a>
</td>
<td align="center" width="200px">
<a href="https://github.com/hyunji0348">
<img height="150px" width="150px" src="https://avatars.githubusercontent.com/hyunji0348"/>
</a>
<br />
<a href="https://github.com/hyunji0348">๋กœ์ปฌ/๊น€ํ˜„์ง€</a>
</td>
<td align="center" width="200px">
<a href="https://github.com/mmije0ng">
<img height="150px" width="150px" src="https://avatars.githubusercontent.com/mmije0ng"/>
</a>
<br />
<a href="https://github.com/mmije0ng">์— ์ œ์ด/๋ฐ•๋ฏธ์ •</a>
</td>
<td align="center" width="200px">
<a href="https://github.com/Hanjun2022">
<img height="150px" width="150px" src="https://avatars.githubusercontent.com/Hanjun2022"/>
</a>
<br />
<a href="https://github.com/Hanjun2022">์ค€/์ „ํ•œ์ค€</a>
</td>
</tr>
</table>

&nbsp;
## ๐Ÿ—‚ ERD
<img width="972" alt="Image" src="https://github.com/user-attachments/assets/f6805244-44b5-45b1-9e47-c47521d8d53a" />

&nbsp;
## ๐Ÿ›  Backend Architecture
<img width="2001" height="1590" alt="image" src="https://github.com/user-attachments/assets/e2cede04-6627-4bb0-bebc-42dc23e1a276" />


&nbsp;
## ๐Ÿš€ git flow
- `main`
- ํ”„๋กœ์ ํŠธ ์ตœ์ข… merge
- ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ ์„ธํŒ…, ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ๋ธŒ๋žœ์น˜, ํ•ญ์ƒ ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ์œ ์ง€
- `develop`
- ๋ฐ๋ชจ๋ฐ์ด ์ „๊นŒ์ง€ ์™„์„ฑํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๊ณ„์†ํ•ด์„œ merge
- ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ๋ธŒ๋žœ์น˜, ํ•ญ์ƒ ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ์œ ์ง€
- `{type}/{description}`: ๊ฐœ๋ฐœ ๋ธŒ๋žœ์น˜
- ์˜ˆ:ย `feat/login`, `fix/login-token`

&nbsp;
## ๐Ÿ’ป Commit Message Convention

| Type | Description |
| -------------------- | ------------------------------------------------------------ |
| **Feat** | ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€ |
| **Fix** | ๋ฒ„๊ทธ ์ˆ˜์ • |
| **Docs** | ๋ฌธ์„œ ์ˆ˜์ • |
| **Style** | ์ฝ”๋“œ formatting, ์„ธ๋ฏธ์ฝœ๋ก  ๋ˆ„๋ฝ, ์ฝ”๋“œ ์ž์ฒด์˜ ๋ณ€๊ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ |
| **Refactor** | ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง |
| **Test** | ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ๋ฆฌํŒฉํ† ๋ง ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ถ”๊ฐ€ |
| **Chore** | ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ˆ˜์ •, ๊ทธ ์™ธ ๊ธฐํƒ€ ์ˆ˜์ • (์˜ˆ: .gitignore) |
| **Design** | CSS ๋“ฑ ์‚ฌ์šฉ์ž UI ๋””์ž์ธ ๋ณ€๊ฒฝ |
| **Comment** | ํ•„์š”ํ•œ ์ฃผ์„ ์ถ”๊ฐ€ ๋ฐ ๋ณ€๊ฒฝ |
| **Rename** | ํŒŒ์ผ ๋˜๋Š” ํด๋” ๋ช…์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์˜ฎ๊ธฐ๋Š” ์ž‘์—…๋งŒ์ธ ๊ฒฝ์šฐ |
| **Remove** | ํŒŒ์ผ์„ ์‚ญ์ œํ•˜๋Š” ์ž‘์—…๋งŒ ์ˆ˜ํ–‰ํ•œ ๊ฒฝ์šฐ |
| **!BREAKING CHANGE** | ์ปค๋‹ค๋ž€ API ๋ณ€๊ฒฝ์˜ ๊ฒฝ์šฐ |
| **!HOTFIX** | ๊ธ‰ํ•˜๊ฒŒ ์น˜๋ช…์ ์ธ ๋ฒ„๊ทธ๋ฅผ ๊ณ ์ณ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ |

ex. `Feat : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€`
# [์„ฑ๋Šฅ ๊ฐœ์„  ๋ณด๊ณ ์„œ] ํ™ˆ ํ™”๋ฉด API ๋‹จ๊ณ„๋ณ„ ์ตœ์ ํ™” ๋ฐ 1,000 VUs ๊ฐ€์šฉ์„ฑ ๊ฒ€์ฆ

๋ณธ ๋ณด๊ณ ์„œ๋Š” ํ™ˆ ํ™”๋ฉด์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ API๋ฅผ ๋Œ€์ƒ์œผ๋กœ, ์ดˆ๊ธฐ ์„ฑ๋Šฅ ์ธก์ •๋ถ€ํ„ฐ ๋กœ์ง/์ธํ”„๋ผ/์•„ํ‚คํ…์ฒ˜ ์ตœ์ ํ™”์— ๋”ฐ๋ฅธ ์‹œ์Šคํ…œ ์ž„๊ณ„์น˜ ๋ณ€ํ™”๋ฅผ ์ •๋Ÿ‰์ ์œผ๋กœ ๋ถ„์„ํ•œ ๊ธฐ๋ก์ž…๋‹ˆ๋‹ค.

---

## 1. ์‹คํ—˜ ๊ฐœ์š” ๋ฐ ํ™˜๊ฒฝ

### 1.1 ์‹คํ—˜ ํ™˜๊ฒฝ ๋ฐ ์‹œ๋‚˜๋ฆฌ์˜ค
- **ํ…Œ์ŠคํŠธ ๋„๊ตฌ**: k6 (ramping-vus)
- **ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค**: 32๋ถ„๊ฐ„ ๊ฐ€์ƒ ์‚ฌ์šฉ์ž(VU)๋ฅผ 1์—์„œ 1,000๊นŒ์ง€ 13๋‹จ๊ณ„์— ๊ฑธ์ณ ์ ์ง„์  ์ฆ๊ฐ€
- **๋Œ€์ƒ API**: ํ™ˆ ํ™”๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๊ฒŒ์‹œ๋ฌผ ์ •๋ณด ๋ฐ˜ํ™˜ API (์ข‹์•„์š”/๋Œ“๊ธ€ ์ˆ˜ ํฌํ•จ)
- **๋ชจ๋‹ˆํ„ฐ๋ง**: Prometheus, Grafana
- **๋ฐฑ์—”๋“œ**: Spring Boot(3.0.0), Java(17)
- **์ธํ”„๋ผ**: AWS (EC2, RDS), Docker

### 1.2 ์‹คํ—˜ ์ง€ํ‘œ ๋ฐ ๋ชฉํ‘œ
- **์—๋Ÿฌ์œจ (http_req_failed)**: ๋ชฉํ‘œ < 1.0%
- **์‘๋‹ต ์‹œ๊ฐ„ (http_req_duration)**: ํ•ต์‹ฌ ๋ชฉํ‘œ p(95) < 2.0s / ๊ฐ€์ด๋“œ๋ผ์ธ p(99) < 5.0s
- **์ฒ˜๋ฆฌ๋Ÿ‰ (http_reqs)**: VU ์ฆ๊ฐ€์— ๋”ฐ๋ฅธ RPS(Throughput) ์„ ํ˜• ์ฆ๊ฐ€ ์—ฌ๋ถ€ ํ™•์ธ

---

## 2. [v1] Baseline: ๊ธฐ์กด ์ฝ”๋“œ ๋ถ„์„ (N+1 ๋ฐœ์ƒ ๊ตฌ์กฐ)

### ๐Ÿšฉ ๊ธฐ์กด ๋กœ์ง ๋ฐ ๋ฌธ์ œ์ 
- **๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ตฌ์กฐ**: ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ(1ํšŒ) + ๊ฐ ๊ฒŒ์‹œ๋ฌผ๋ณ„ ์ข‹์•„์š” COUNT(NํšŒ) + ๋Œ“๊ธ€ COUNT(NํšŒ)
- **๋ณ‘๋ชฉ ์›์ธ**: ์ด **1 + 2N ์ฟผ๋ฆฌ**๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ, ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€ ์‹œ DB I/O ๋ถ€ํ•˜ ๋ฐ ์ปค๋„ฅ์…˜ ์ ์œ  ์‹œ๊ฐ„ ๊ธ‰์ฆ

### 2.1 ๊ตฌ๊ฐ„๋ณ„ ์„ฑ๋Šฅ ๋ณ€ํ™” ๋ถ„์„
- **โ‘  [์•ˆ์ • ๊ตฌ๊ฐ„] VUs 0~500๋ช…**: RPS๊ฐ€ ์„ ํ˜•์ ์œผ๋กœ ์ƒ์Šนํ•˜๋ฉฐ p(95) 1์ดˆ ๋ฏธ๋งŒ ์œ ์ง€.
- **โ‘ก [์ง€์—ฐ ๋ฐœ์ƒ ๊ตฌ๊ฐ„] VUs 500~800๋ช…**: 500๋ช… ์ง€์ ์—์„œ **์„ฑ๋Šฅ ๋ณ€๊ณก์ (Elbow Point)** ๋ฐœ์ƒ. ์š”์ฒญ์ด Queue์— ์Œ“์ด๋ฉฐ ์ง€์—ฐ ์‹œ๊ฐ„ ๊ธ‰์ฆ.
- **โ‘ข [๋ถ•๊ดด ๋ฐ ์ž„๊ณ„ ๊ตฌ๊ฐ„] VUs 800~1,000๋ช…**: p(95) ์‘๋‹ต ์‹œ๊ฐ„์ด **6.7s**๋กœ ์น˜์†Ÿ์œผ๋ฉฐ RPS๋Š” **155 req/s**์—์„œ ์ •์ฒด(Saturation).

<img width="1280" height="675" alt="v1_result_1" src="https://github.com/user-attachments/assets/d045e6f8-4323-4782-acf0-0a24ae35b3da" />
<img width="1280" height="989" alt="v1_result_2" src="https://github.com/user-attachments/assets/4ea13c6b-080b-4892-b88d-4475ffbbf03f" />

### 2.2 ์‹คํ—˜ ๊ฒฐ๊ณผ (1,000 VUs)
| ์ง€ํ‘œ ํ•ญ๋ชฉ | ์ธก์ • ๊ฒฐ๊ณผ | ํŒ์ • ๋ฐ ์˜๋ฏธ |
| :--- | :--- | :--- |
| **p(95) Latency** | **6.7s** | **Fail**: ๋ชฉํ‘œ์น˜(2s) ๋Œ€๋น„ 3๋ฐฐ ์ด์ƒ ์ง€์—ฐ |
| **p(99) Latency** | **7.94s** | **Fail**: ์ตœ์•…์˜ ์ƒํ™ฉ ์‘๋‹ต์„ฑ ๋ถ•๊ดด |
| **Peak RPS** | **155 req/s** | ์ธํ”„๋ผ ํ™˜๊ฒฝ์˜ ๋ฌผ๋ฆฌ์  ์ฒ˜๋ฆฌ ํ•œ๊ณ„ ๋…ธ์ถœ |
| **Error Rate** | **0.00% (15๊ฑด)** | `dial: i/o timeout` ๋“ฑ ์†Œ์ˆ˜ ํ•˜๋“œ ์—๋Ÿฌ ๋ฐœ์ƒ |

---

## 3. [v2] 1์ฐจ ๊ฐœ์„ : QueryDSL ๊ธฐ๋ฐ˜ ๋‹จ์ผ ์กฐํšŒ (N+1 ์ œ๊ฑฐ)

### โœ… ๋ณ€๊ฒฝ ์‚ฌํ•ญ (What was changed?)
- **์ฟผ๋ฆฌ ํ†ตํ•ฉ**: QueryDSL์„ ์ด์šฉํ•ด `JOIN` ๋ฐ `GROUP BY`๋ฅผ ํ™œ์šฉํ•œ **๋‹จ์ผ ์ง‘๊ณ„ ์ฟผ๋ฆฌ**๋กœ ๋ฆฌํŒฉํ† ๋ง
- **์ตœ์ ํ™” ๊ธฐ๋ฒ•**: `COUNT(DISTINCT ...)`๋ฅผ ์ ์šฉํ•˜์—ฌ ์กฐ์ธ ์‹œ ์ค‘๋ณต ์ง‘๊ณ„ ๋ฐฉ์ง€
- **DTO Projection**: Entity ๋Œ€์‹  ์กฐํšŒ ์ „์šฉ DTO(**HomePostRow**)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋ถ€ํ•˜ ์ ˆ๊ฐ

### 3.1 ๊ตฌ๊ฐ„๋ณ„ ์„ฑ๋Šฅ ๋ณ€ํ™” ๋ถ„์„
- **โ‘  [์„ฑ๋Šฅ ๊ฐœ์„  ํ™•์ธ]**: ์ด์ „ ํ…Œ์ŠคํŠธ ๋Œ€๋น„ RPS๊ฐ€ **์ตœ๋Œ€ 268.29 req/s**๊นŒ์ง€ ์ƒ์Šนํ•˜๋ฉฐ ์—ฐ์‚ฐ ํšจ์œจ **88%** ํ–ฅ์ƒ ์ž…์ฆ.
- **โ‘ก [๋ณ‘๋ชฉ ์ž”์กด]**: 600 VUs ์ดํ›„ ์ฒ˜๋ฆฌ๋Ÿ‰์€ ๋Š˜์—ˆ์œผ๋‚˜ DB ์ปค๋„ฅ์…˜ ์ž์› ๋ถ€์กฑ์œผ๋กœ ์ธํ•œ ํƒ€์ž„์•„์›ƒ ๊ฒฝ๊ณ  ์žฌ๋ฐœ์ƒ.
- **โ‘ข [์ง€์—ฐ ๊ฐ์†Œ]**: p(95) ์‘๋‹ต ์‹œ๊ฐ„์€ **3.38s**๋กœ v1 ๋Œ€๋น„ ์•ฝ **50% ๊ฐœ์„ **๋˜์—ˆ์œผ๋‚˜ ๋ชฉํ‘œ์น˜(2s)์—๋Š” ๋ฏธ๋‹ฌ.

<img width="1280" height="716" alt="v2_result_1" src="https://github.com/user-attachments/assets/23708d85-d470-4123-b3c8-b7e1b36b4a21" />
<img width="1280" height="933" alt="v2_result_2" src="https://github.com/user-attachments/assets/914a33b3-17ee-44ec-b4be-3f14a6f38450" />

### 3.2 ์„ฑ๋Šฅ ์ง€ํ‘œ ๋น„๊ต (v1 vs v2)
| ์ง€ํ‘œ ํ•ญ๋ชฉ | v1 (Baseline) | v2 (๋กœ์ง ์ตœ์ ํ™”) | ์„ฑ๊ณผ |
| :--- | :--- | :--- | :--- |
| **p(95) Latency** | 6.7s | **3.38s** | **50% ๋‹จ์ถ•** |
| **Avg Throughput** | 142.4 req/s | **268.29 req/s** | **88% ํ–ฅ์ƒ** |
| **Peak RPS** | 155 req/s | **312 req/s** | **101% ํ–ฅ์ƒ** |

---

## 4. [v3] 2์ฐจ ๊ฐœ์„ : ์ธํ”„๋ผ ์„ค์ • ์ตœ์ ํ™” (WAS/DB ํŠœ๋‹)

### โœ… ๋ณ€๊ฒฝ ์‚ฌํ•ญ (What was changed?)
- **HikariCP**: `maximum-pool-size: 30`, `connection-timeout: 30000` (์ปค๋„ฅ์…˜ ๋ถ€์กฑ ํ•ด์†Œ)
- **Tomcat**: `threads.max: 400`, `max-connections: 8192` (๋™์‹œ ์š”์ฒญ ์ˆ˜์šฉ๋Ÿ‰ ์ฆ๋Œ€)
- **RDS**: DB ํŒŒ๋ผ๋ฏธํ„ฐ ๊ทธ๋ฃน ์ˆ˜์ •์„ ํ†ตํ•ด `max_connections: 300` ํ™•๋ณด

### 4.1 ๊ตฌ๊ฐ„๋ณ„ ์„ฑ๋Šฅ ๋ณ€ํ™” ๋ถ„์„
- **โ‘  [์ธํ”„๋ผ ๋ณ‘๋ชฉ ํ•ด์†Œ]**: v2 ๋Œ€๋น„ Peak RPS๊ฐ€ **358 req/s**๋กœ ์•ฝ **130%** ์ƒ์Šนํ•˜๋ฉฐ ์„ค์ • ํŠœ๋‹ ํšจ๊ณผ ์ž…์ฆ.
- **โ‘ก [์ฒ˜๋ฆฌ ์šฉ๋Ÿ‰ ๊ทน๋Œ€ํ™”]**: ์ด ์ฒ˜๋ฆฌ ์š”์ฒญ ์ˆ˜ **584,006๊ฑด**์œผ๋กœ ํ™•์žฅ.
- **โ‘ข [๋ฌผ๋ฆฌ ์ž„๊ณ„์  ์‹๋ณ„]**: ์„ค์ •์„ ํ™•์žฅํ–ˆ์Œ์—๋„ p(95)๊ฐ€ **3.30s**์—์„œ ์ •์ฒด๋จ. ํ˜„์žฌ ๊ตฌ์กฐ์ƒ **๋ฌผ๋ฆฌ์  Disk I/O ํฌํ™”**๋กœ ํŒ๋‹จ๋จ.

<img width="1280" height="717" alt="v3_result_1" src="https://github.com/user-attachments/assets/cc0ab432-26e8-43e1-b355-80ed0748dd11" />
<img width="1280" height="322" alt="v3_result_3" src="https://github.com/user-attachments/assets/08322a78-6dff-40aa-8f83-371ab8de1951" />

---

## 5. [v4] ๊ฐœ์„ : Redis ์บ์‹œ ๋„์ž… (In-memory ์•„ํ‚คํ…์ฒ˜)

### โœ… ๋ณ€๊ฒฝ ์‚ฌํ•ญ (What was changed?)
- **์บ์‹ฑ ์ „๋žต**: ํ™ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐ์ดํ„ฐ๋ฅผ `category:{PostType}` ํ‚ค ๊ตฌ์กฐ๋กœ **Redis**์— ์ €์žฅ (In-memory)
- **์œ ํšจ ์ •์ฑ…**: `TTL 60์ดˆ` ์ ์šฉ ๋ฐ ์ข‹์•„์š”/๋Œ“๊ธ€ ๋ณ€๊ฒฝ ์‹œ `afterCommit` ์‹œ์ ์— **์„ ํƒ์  ์บ์‹œ ๋ฌดํšจํ™”(Evict)**
- **์ง๋ ฌํ™”**: `GenericJackson2JsonRedisSerializer`๋ฅผ ํ†ตํ•œ DTO ์ง๋ ฌํ™”

### 5.1 ๊ตฌ๊ฐ„๋ณ„ ์„ฑ๋Šฅ ๋ณ€ํ™” ๋ถ„์„
- **โ‘  [์‘๋‹ต ํ˜์‹ ]**: ๋ฌผ๋ฆฌ Disk๋ฅผ ํƒ€์ง€ ์•Š๋Š” ์กฐํšŒ๋กœ p(95) ์‘๋‹ต ์‹œ๊ฐ„์„ **2.56s**๋กœ ๋‹จ์ถ• (**v3 ๋Œ€๋น„ 22% ์ถ”๊ฐ€ ๊ฐœ์„ **).
- **โ‘ก [RPS ๊ทน๋Œ€ํ™”]**: Peak RPS **498** ๋‹ฌ์„ฑ. ์‹œ์Šคํ…œ ์ฒ˜๋ฆฌ ์šฉ๋Ÿ‰์ด ์ดˆ๊ธฐ ๋Œ€๋น„ ์•ฝ **3.2๋ฐฐ** ํ™•์žฅ๋จ.
- **โ‘ข [์•ˆ์ •์„ฑ ์œ ์ง€]**: ์ด ์š”์ฒญ ์ˆ˜ **77.3๋งŒ ๊ฑด**์œผ๋กœ ํญ์ฆํ–ˆ์œผ๋‚˜, ์—๋Ÿฌ์œจ **0.009%**๋กœ ์‹ ๋ขฐ์„ฑ ์žˆ๋Š” ์‘๋‹ต ์œ ์ง€.

<img width="1280" height="706" alt="v4_result_1" src="https://github.com/user-attachments/assets/560b66db-4e21-47fa-bfdc-7e07f844d14f" />
<img width="1280" height="584" alt="v4_result_3" src="https://github.com/user-attachments/assets/9678d362-afd9-4005-a415-46f93f8c07bb" />

### 5.2 ์„ฑ๋Šฅ ์ง€ํ‘œ ๋น„๊ต (v1 ~ v4)
| ์ง€ํ‘œ ํ•ญ๋ชฉ | v1 (Baseline) | v2 (๋กœ์ง) | v3 (์„ค์ •) | v4 (Redis) | ์„ฑ๊ณผ (v1 vs v4) |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **p(95) Latency** | 6.71s | 3.38s | 3.30s | **2.56s** | **62% ๋‹จ์ถ•** |
| **Avg Throughput**| 142.4 | 268.29 | 300.49 | **401.7** | **182% ํ–ฅ์ƒ** |
| **Peak RPS** | 155 | 312 | 358 | **498** | **221% ํ–ฅ์ƒ** |
| **Total Requests**| 27.7๋งŒ | 52.0๋งŒ | 58.4๋งŒ | **77.3๋งŒ** | **2.8๋ฐฐ ์ฆ๊ฐ€** |

---

## 6. ์ตœ์ข… ์„ฑ๋Šฅ ๊ฐœ์„  ๋ชฉํ‘œ ๋ฐ ๋‹ฌ์„ฑ ํ˜„ํ™ฉ ์š”์•ฝ

| ๊ตฌ๋ถ„ | ๋ชฉํ‘œ์น˜ (Thresholds) | v1 (๊ธฐ์กด) | v4 (์ตœ์ข…) | ๊ฒฐ๊ณผ |
| :--- | :--- | :--- | :--- | :--- |
| **p(95) Latency** | **2.0s ๋ฏธ๋งŒ** | 6.71s | **2.56s** | **๋ฏธ๋‹ฌ (CPU ์ž์› ์ž„๊ณ„)** |
| **p(99) Latency** | **5.0s ๋ฏธ๋งŒ** | - | **3.98s** | **ํ†ต๊ณผ** |
| **Error Rate** | **1.0% ๋ฏธ๋งŒ** | 0.005% | **0.009%** | **ํ†ต๊ณผ** |

**ํ–ฅํ›„ ๋ชฉํ‘œ**:
๋กœ์ง, ์ธํ”„๋ผ, ์บ์‹ฑ ์ตœ์ ํ™”๋ฅผ ํ†ตํ•ด ๋น„์•ฝ์ ์ธ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ๊ฑฐ๋‘์—ˆ์œผ๋‚˜, 1,000 VU ํ™˜๊ฒฝ์—์„œ ๋‹จ์ผ ์ธ์Šคํ„ด์Šค์˜ CPU ๋ถ€ํ•˜๋กœ ์ธํ•ด p(95) 2.0s ๋ชฉํ‘œ์—๋Š” ๋ฏธ๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ **์ธ์Šคํ„ด์Šค ํ™•์žฅ(Scale-out)** ๋ฐ **๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ(ALB)** ์ ์šฉ์„ ํ†ตํ•ด ์ž์› ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐํ•˜๊ณ  ์ตœ์ข… ๋ชฉํ‘œ ์ง€ํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.
Loading