티스토리 뷰
1. Virtual Thread 소개
Virtual Thread는 JDK 21에 정식 Feature로 추가된 경량 스레드로, OpenJDK의 Project Loom에서 개발되었습니다. 이 프로젝트는 Java의 동시성 (Concurreny) 처리 개선을 목표로 2017년에 시작되었습니다.
2. Thread와 Virtual Thread의 구조
Java의 Thread는 OS의 Kernel Thread에 1:1 구조로 Thread 생성 시 JNI를 통해 OS에 Kerner Thread가 생성됩니다. 생성된 Thread는 OS에 의해 스케줄링됩니다.
Virtual Thread는 Carrier Thread에 1:N 구조로 여러 Virtual Thread를 하나의 Carrier Thread에 돌아가면서 실행됩니다. 생성된 Virtual Thread는 JVM에 의해 스케줄링됩니다.
3. Thread와 비교 시 Virtual Thread의 개선점
- Thread의 생성과 관리 비용을 개선
- OS의 Kernel Thread는 OS에 의해 생성되고 스케줄링되어 CPU에서 실행됩니다.
- JVM은 JNI를 통해 Kernel Thread를 제어합니다.
- 이러한 구조는 Thread의 생성과 Context Switching 시 높은 비용이 발생합니다.
- Virtual Thread는 JVM 내부에서 Virtual Thread의 생성과 스케줄링을 직접 관리합니다.
- Thread의 메모리 사용량을 개선
특성 Thread Virtual Thread 초기 메모리 약 1MB(기본 스택 크기) 약 몇 KB(필요에 따라 증가) 최대 메모리 스택 크기 고정 스택 크기 동적 증가 Thread 수 제한적(메모리 소모가 큼) 수백만 개 생성 가능 - 제한된 개수만 생성 가능한 Thread를 개선
- Thread는 OS의 Kernel Thread를 1:1로 Wrapping한 Platform Thread입니다.
- OS의 Kernel Thread는 OS에서 관리되고 생성 개수가 제한되어 있어, Thread 역시 생성이 제한적입니다.
- Virtual Thread는 OS의 Kernel Thread와 1:1 Wrapping 되지 않고
JVM 내부에서 관리되기 때문에 Heap 범위 내에서 제한 없이 많은 Virtual Thread의 생성이 가능합니다.
- 블로킹 I/O 처리 시 Thread의 대기 상태를 개선
- Thread는 블로킹 I/O 작업 시 대기 상태로 전환되고, 작업이 완료될 때까지 다른 작업을 처리할 수 없습니다.
- Idle 상태의 Thread가 생깁니다.
- Virtual Thread는 블로킹 I/O 작업 시 Carrier Thread에서 Unmount되고, 다른 Virtual Thread가 해당 Carrier Thread에 Mount되어 Carrier Thread는 Idle 상태가 되지 않고 계속 동작하게 됩니다.
4. Coroutine(비동기 프로그래밍)과 비교 시 Virtual Thread의 장점
- 제어 흐름 유지
- 비동기 프로그래밍에서는 조건문이나 반복문과 같은 단순한 제어 흐름을 구현할 때 복잡한 코드 구조가 발생할 수 있습니다.
- Callback 지옥과 같은 문제로 인해 부가적인 코드가 많아질 수 있습니다.
- Virtual Thread를 사용하면 이러한 코드를 동기식으로 간단하게 작성 가능하게 해줍니다.
- Context 유지
- 비동기 프로그래밍은 요청이 여러 Thread를 넘나들며 처리되기 때문에 Context 정보가 스택 트레이스에 누적되지 않는 문제가 발생합니다.
- 이로 인해 스택 트레이스가 쓸모가 없어집니다.
- Virtual Thread는 Context를 유지하여 디버깅 및 문제 분석을 가능하게 해줍니다.
5. Continuation
Continuation은 Virtual Thread의 핵심 기술로, 프로그램 실행을 일시 중지하고 상태를 저장한 후, 저장된 상태를 다시 불러와 실행을 재개할 수 있게 해줍니다. 이를 통해 개발자는 동기식 코드 작성의 편리함을 유지하면서도 비동기 프로그래밍의 성능 이점을 얻을 수 있습니다.
6. 성능 테스트(by Spring Boot v3.4.1, JDK 21)
Tomcat Thread Pool 설정
server:
tomcat:
threads:
max: 50 # 스레드 최대 생성 개수
min-spare: 5 # Idle 상태의 스레드 개수
spring:
threads:
virtual:
enabled: true # Virtual Thread 활성화/비활성화
테스트 코드
@RequiredArgsConstructor
@RestController
public class ThreadController {
@GetMapping("/test-threads")
public String testThreads() throws InterruptedException {
Thread.sleep(1000); // 1초 Sleep
return "Hello Java~";
}
}
Virtual Thread On/Off에 따른 테스트 결과
- Threads: 41.8 TPS
- Virtual Threads: 72.4 TPS
- Virtual Threads를 사용할 경우, TPS가 약 73% 증가하여 성능이 크게 향상되는 것을 확인할 수 있었다.
하지만, 테스트는 성능 차이를 내기위해 극한(?)의 상황을 만들어 놓은거라 요청이 적은 환경은 이보다 적은 성능 향상을 확인할 수 있었다.
7. 유의사항
- ThreadLocal 사용 시 메모리 증가 주의
- Virtual Thread는 작업당 하나씩 생성하며, 각각 독립된 ThreadLocal 공간을 가집니다.
의도치 않게 메모리 사용량이 증가할 수 있습니다. - 방안: 컨텍스트 전파가 필요한 경우 ScopedValue 또는 ThreadLocalAccessor 사용합니다.
- Virtual Thread는 작업당 하나씩 생성하며, 각각 독립된 ThreadLocal 공간을 가집니다.
- Virtual Thread Pinning Issue(JDK 24에서 개선 예정)
- synchronized 블록에 진입하면 Virtual Thread가 Carrier Thread에서 Unmount 못하는 상태(Pinning)가 발생하여
성능 저하가 발생합니다. - 방안 : ReentrantLock 등 java.util.concurrent 패키지의 락 구현체를 사용합니다.
- synchronized 블록에 진입하면 Virtual Thread가 Carrier Thread에서 Unmount 못하는 상태(Pinning)가 발생하여
- 과도한 동시성으로 인한 리소스 부족
- DB Connection Pool 같은 제한된 자원에 동시 접근이 증가해 Timeout이 발생 가능합니다.
(e.g: SQLTransientConnectionException) - 방안: Semaphore를 활용해 동시성을 제어하거나, Connection Pool 크기와 Virtual Thread 수를 적절히 조정하여 해결합니다.
- DB Connection Pool 같은 제한된 자원에 동시 접근이 증가해 Timeout이 발생 가능합니다.
- CPU Bound 작업에는 비효율적
- CPU Bound 작업은 Virtual Thread의 Mount/Unmount 오버헤드로 인해 Platform Thread보다 비효율적입니다.
- 적합한 환경: IO Bound 작업에 효율적입니다.
- Structured Concurrency 활용
- 기존 CompletableFuture 체인은 작업 실패 시 리소스 누수나 에러 전파가 불명확합니다.
- 방안: StructuredTaskScope를 사용해 작업 그룹의 생명주기를 명시적으로 관리합니다.
'TIL > Java' 카테고리의 다른 글
GSON Type 정의 관련 정리 (0) | 2017.11.21 |
---|---|
Marshalling and Unmarshalling by the JAXB (0) | 2016.11.15 |
injecting XML(Document) into SOAP body(SOAPBody) (0) | 2016.11.15 |
Convert date(String) to XMLGregorianCalendar (0) | 2016.11.15 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- Rolling-Restart
- springboot
- DATABASE
- Java
- JAXB
- HLS
- jdk7
- ffmpeg
- oid
- JDK21
- DB
- popupWindow
- fluentd
- onbeforeunload
- Virtual Thread
- development
- JPA
- HDFS
- Programming
- CentOS
- jdk6
- elasticsearch
- springframework
- AVIOContext
- HTTP Live Streaming
- Spring
- C/C++
- libavformat
- programmer
- springjpa
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함