Skip to content

Commit 0291f9b

Browse files
authored
[2] 기존 스레드 vs 가상 스레드 성능 비교
[2] 기존 스레드 vs 가상 스레드 성능 비교
2 parents c35ed1a + 3eee114 commit 0291f9b

12 files changed

Lines changed: 6065 additions & 18 deletions

README.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Virtual Threads Performance Test 🚀
2+
3+
Java 21의 가상 스레드(Virtual Threads)와 전통적인 플랫폼 스레드(Platform Threads)의 성능을 실제로 비교하는 프로젝트입니다.
4+
5+
## 핵심 포인트
6+
7+
**코드는 완전히 동일하고, 설정 하나만 바꿔서 테스트합니다!**
8+
9+
```yaml
10+
# application-virtual.yml
11+
spring:
12+
threads:
13+
virtual:
14+
enabled: true # 이것만으로 끝!
15+
```
16+
17+
## 빠른 시작
18+
19+
### 1. 일반 플랫폼 스레드 테스트
20+
21+
```bash
22+
# 애플리케이션 실행
23+
./gradlew bootRun
24+
25+
# 엔드포인트 동작 확인 (다른 터미널)
26+
curl http://localhost:8080/api/sleep-test
27+
# 출력: OK (100ms 소요)
28+
29+
# JMeter로 성능 테스트
30+
jmeter
31+
# File → Open → jmeter/Spring-MVC-Performance-Test.jmx
32+
# Run → Start
33+
34+
# 결과 확인 후 종료
35+
Ctrl+C
36+
```
37+
38+
### 2. 가상 스레드 테스트 ⚡
39+
40+
```bash
41+
# 가상 스레드로 실행
42+
./gradlew bootRun --args='--spring.profiles.active=virtual'
43+
44+
# 동일한 JMeter 테스트 실행
45+
46+
# 결과 비교!
47+
```
48+
49+
### 3. 스레드 타입 확인
50+
51+
```bash
52+
# 플랫폼 스레드
53+
curl http://localhost:8080/api/thread-info
54+
# 출력: Thread Type: 🐌 Platform Thread
55+
56+
# 가상 스레드
57+
curl http://localhost:8080/api/thread-info
58+
# 출력: Thread Type: 🚀 Virtual Thread
59+
```
60+
61+
## 주요 기능
62+
63+
### 순수 I/O 지연 시뮬레이션 ⏱️
64+
65+
`Thread.sleep(100)`으로 실제 운영 환경의 I/O 대기 시간을 시뮬레이션합니다:
66+
67+
- **시뮬레이션 시간**: 고정 100ms
68+
- **테스트 대상**: `/api/sleep-test` 엔드포인트
69+
- **DB 의존성**: 없음 (순수 스레드 성능 테스트)
70+
71+
이 지연 시간 동안:
72+
- **플랫폼 스레드**: 100ms 동안 OS 스레드가 블로킹되어 낭비됨 😴
73+
- **가상 스레드**: carrier thread에서 unmount되어 다른 작업 처리 🚀
74+
75+
## 예상 결과
76+
77+
| 지표 | 플랫폼 스레드 | 가상 스레드 | 차이 |
78+
|------|-------------|------------|------|
79+
| **Throughput** | ~500 req/sec | ~5,000 req/sec | **10배 향상** 🚀 |
80+
| **Response Time (Avg)** | ~500ms | ~100ms | **5배 빠름**|
81+
| **P95 Response Time** | ~1,000ms | ~110ms | **9배 빠름** |
82+
| **Error Rate** | 0~5% | 0% | **안정성 향상**|
83+
| **Platform Thread Count** | 200 (고갈) | 8~16 (CPU 코어 수) | **리소스 절약** 💾 |
84+
| **Virtual Thread Count** | - | 5,000+ | **무제한 동시성** ♾️ |
85+
86+
## 기술 스택
87+
88+
- Java 21
89+
- Spring Boot 3.4.4
90+
- Spring MVC (동일한 코드)
91+
- MySQL 8.0 (선택 사항, 테스트에 미사용)
92+
- Apache JMeter
93+
- Lombok
94+
95+
## 프로젝트 구조
96+
97+
```
98+
├── src/main/java/ex/demo/
99+
│ ├── SleepTestController.java # Thread.sleep(100) 테스트 API ⏱️
100+
│ ├── ThreadInfoController.java # 스레드 타입 확인
101+
│ ├── Comment*.java # 댓글 기능 (참고용)
102+
│ └── SimulatedDelayService.java # 지연 서비스 (참고용)
103+
├── src/main/resources/
104+
│ ├── application.yml # 플랫폼 스레드 (기본)
105+
│ └── application-virtual.yml # 가상 스레드
106+
├── jmeter/
107+
│ └── Spring-MVC-Performance-Test.jmx # JMeter 테스트 플랜
108+
└── docs/
109+
├── performance-test.md # 상세 가이드
110+
└── test-results-template.md # 결과 기록 템플릿
111+
```
112+
113+
## 테스트 시나리오
114+
115+
- **동시 사용자**: 500명
116+
- **램프업 시간**: 30초
117+
- **반복 횟수**: 10회
118+
- **Think Time**: 1초
119+
- **총 요청 수**: 5,000회
120+
- **각 요청 처리 시간**: 100ms (Thread.sleep)
121+
122+
## 가상 스레드란?
123+
124+
**Java 21의 혁신적인 기능**으로, 수백만 개의 경량 스레드를 만들 수 있습니다.
125+
126+
### 전통적인 플랫폼 스레드
127+
128+
```
129+
요청 1 → OS 스레드 1 (1MB 메모리) → DB 대기 중 😴
130+
요청 2 → OS 스레드 2 (1MB 메모리) → DB 대기 중 😴
131+
...
132+
요청 200 → OS 스레드 200 (1MB 메모리) → DB 대기 중 😴
133+
요청 201 → ❌ 스레드 풀 고갈! 대기...
134+
```
135+
136+
### 가상 스레드
137+
138+
```
139+
요청 1 → 가상 스레드 1 → DB 대기 시 OS 스레드 반납
140+
→ OS 스레드는 다른 가상 스레드 처리 🚀
141+
요청 2 → 가상 스레드 2 → DB 대기 시 OS 스레드 반납
142+
...
143+
요청 100만 → 가상 스레드 100만 → 모두 처리 가능! ✅
144+
```
145+
146+
## 가상 스레드의 장점
147+
148+
1. **높은 처리량**: I/O 대기 시간을 낭비하지 않음
149+
2. **낮은 리소스 사용**: OS 스레드 10~20개로 수만 개의 요청 처리
150+
3. **코드 변경 불필요**: 기존 블로킹 코드 그대로 사용
151+
4. **학습 비용 낮음**: Reactive 프로그래밍 불필요
152+
5. **안정성 향상**: 스레드 풀 고갈 없음
153+
154+
## 언제 사용해야 하는가?
155+
156+
### ✅ 가상 스레드 사용 추천
157+
158+
- **I/O Bound 작업**: DB 쿼리, 외부 API 호출, 파일 I/O
159+
- **높은 동시성**: 마이크로서비스, 실시간 채팅, 알림 시스템
160+
- **블로킹 코드 유지**: 기존 코드 마이그레이션 부담 최소화
161+
162+
### ❌ 가상 스레드 효과 없음
163+
164+
- **CPU Bound 작업**: 복잡한 계산, 암호화, 이미지 처리
165+
- **낮은 동시성**: 동시 요청이 적을 때 (< 100)
166+
- **메모리 Bound**: 대용량 데이터 처리
167+
168+
## 주의사항
169+
170+
### Synchronized 블록 피하기
171+
172+
```java
173+
// ❌ 가상 스레드에서 피해야 할 코드
174+
synchronized (lock) {
175+
// I/O 작업
176+
db.query();
177+
}
178+
179+
// ✅ 대신 이렇게
180+
Lock lock = new ReentrantLock();
181+
lock.lock();
182+
try {
183+
db.query();
184+
} finally {
185+
lock.unlock();
186+
}
187+
```
188+
189+
## 참고 자료
190+
191+
- [JEP 444: Virtual Threads](https://openjdk.org/jeps/444)
192+
- [Spring Boot 3.2+ Virtual Threads](https://spring.io/blog/2023/09/09/all-together-now-spring-boot-3-2-graalvm-native-images-java-21-and-virtual)
193+
- [상세 테스트 가이드](docs/performance-test.md)
194+
195+
## 라이선스
196+
197+
MIT License

build.gradle

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ java {
1313
}
1414
}
1515

16+
tasks.withType(JavaCompile) {
17+
options.compilerArgs << '-parameters'
18+
}
19+
1620
configurations {
1721
compileOnly {
1822
extendsFrom annotationProcessor
@@ -26,23 +30,23 @@ repositories {
2630

2731

2832
dependencies {
33+
// Spring MVC
2934
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
3035
implementation 'org.springframework.boot:spring-boot-starter-web'
36+
37+
// Database
38+
runtimeOnly 'com.mysql:mysql-connector-j'
39+
40+
// Lombok
3141
compileOnly 'org.projectlombok:lombok'
32-
runtimeOnly 'com.h2database:h2'
3342
annotationProcessor 'org.projectlombok:lombok'
3443

44+
// Test dependencies
3545
testImplementation 'org.springframework.boot:spring-boot-starter-test'
3646
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
3747
testImplementation 'com.navercorp.fixturemonkey:fixture-monkey-starter:1.1.9'
38-
3948
testCompileOnly 'org.projectlombok:lombok'
4049
testAnnotationProcessor 'org.projectlombok:lombok'
41-
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
42-
implementation 'org.springframework.boot:spring-boot-starter-web'
43-
// ... 다른 의존성들 ...
44-
45-
4650
}
4751

4852
tasks.named('test') {

0 commit comments

Comments
 (0)