Virtual Thread
๊ฐ์ ์ค๋ ๋๋ Java 21์์ ์ ์ ๋์ ๋ ๊ฒฝ๋ ์ค๋ ๋ ๋ชจ๋ธ๋ก, ๊ธฐ์กด์ ํ๋ซํผ ์ค๋ ๋๊ฐ ๊ฐ์ง ๋ฆฌ์์ค ์ข ์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ , ๋จ์ํ ๋๊ธฐ์ ์ฝ๋๋ก ๋์ ์ฒ๋ฆฌ๋์ ๋ฌ์ฑํ๊ธฐ ์ํด ์ค๊ณ๋์๋ค.
OS ์ค๋ ๋์ 1:1๋ก ๋งคํ๋์ง ์๊ณ JVM ์ค์ผ์ค๋ฌ๋ฅผ ํตํด ๊ด๋ฆฌ๋๋ ๋ ผ๋ฆฌ์ ์คํ ๋จ์
์๋ฐฑ๋ง ๊ฐ์ ์ค๋ ๋๋ฅผ ๋์์ ์์ฑํ๋๋ผ๋ ๋ฉ๋ชจ๋ฆฌ์ CPU ์ค๋ฒํค๋๊ฐ ๊ทนํ ์ ์
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๋ณต์ก์ฑ ์์ด ๊ธฐ์กด ์๋ธ๋ฆฟ ๊ธฐ๋ฐ์ Thread-per-request ๋ชจ๋ธ ์ ์ง ๊ฐ๋ฅ
๋ธ๋กํน I/O ์์ ์ด ๋ฐ์ํด๋ OS ์ค๋ ๋ ์ ์ ์์ด ํจ์จ์ ์ผ๋ก ๋๊ธฐํ ์ ์๋๋ก ์ค๊ณ
๋์
๋ฐฐ๊ฒฝ ๋ฐ ํ๊ณ ๊ทน๋ณต
์ ํต์ ์ธ ์๋ฐ ๋๊ธฐํ ๋ชจ๋ธ์ ์ด์์ฒด์ ์ ์ปค๋ ์ค๋ ๋๋ฅผ ๋ํํ ํ๋ซํผ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด ๋ฐฉ์์ ํ์ฅ์ฑ ์ธก๋ฉด์์ ๋ช ํํ ํ๊ณ๋ฅผ ์ง๋๋ค.
ํ๋ซํผ ์ค๋ ๋์ ๋น์ฉ ๋ฌธ์
๋ฉ๋ชจ๋ฆฌ ์ ์ : ํ๋ซํผ ์ค๋ ๋๋ ์์ฑ ์ ์ฝ 1MB์ ๊ณ ์ ๋ ์คํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น
์์ฑ ๋น์ฉ: OS ์ปค๋์ด ์ง์ ๊ฐ์ ํ์ฌ ์ค๋ ๋๋ฅผ ์์ฑํ๋ฏ๋ก ์๊ฐ ์๋ชจ๊ฐ ํผ
์ปจํ ์คํธ ์ค์์นญ: ์ค๋ ๋ ๊ฐ ์ ํ ์ ์ปค๋ ๋ชจ๋ ๊ถํ ๋ณ๊ฒฝ์ด ํ์ํ์ฌ CPU ์ฌ์ดํด ๋ญ๋น ๋ฐ์
๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ชจ๋ธ์ ๋ณํ
ํ๋์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ CPU ์ฐ์ฐ๋ณด๋ค I/O(DB ํธ์ถ, API ์ฐ๋) ๋๊ธฐ ์๊ฐ์ด ๋ ํผ
ํ๋ซํผ ์ค๋ ๋๋ I/O ๋ธ๋กํน ๋ฐ์ ์ ํด๋น ์ค๋ ๋๊ฐ ์๋ฌด ์ผ๋ ํ์ง ๋ชปํ๊ณ ์์์ ์ ์ ํ๋ ๋ญ๋น ๋ฐ์
๊ฐ์ ์ค๋ ๋๋ ์ด๋ฌํ ๋๊ธฐ ์๊ฐ์ ์์์ ๋ฐ๋ฉํ๋๋ก ์ค๊ณ๋์ด ์์ ํจ์จ์ฑ ๊ทน๋ํ
๋ด๋ถ ๋์ ์๋ฆฌ์ ์ค์ผ์ค๋ง
๊ฐ์ ์ค๋ ๋๋ JDK ๋ด๋ถ์ ForkJoinPool์ ์ค์ผ์ค๋ฌ๋ก ์ฌ์ฉํ๋ฉฐ, ์ค์ ์ฐ์ฐ์ ์ํํ๋ ํ๋ซํผ ์ค๋ ๋์ธ ์บ๋ฆฌ์ด ์ค๋ ๋(Carrier Thread) ์์์ ์คํ๋๋ค.
๋ง์ดํธ(Mount)์ ์ธ๋ง์ดํธ(Unmount)
๊ฐ์ ์ค๋ ๋๊ฐ ์คํ๋ ๋ ์ค์ผ์ค๋ฌ์ ์ํด ์บ๋ฆฌ์ด ์ค๋ ๋์ ํ ๋น๋๋ ๊ณผ์ ์ ๋ง์ดํธ๋ผ๊ณ ํ๋ฉฐ, ๊ทธ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
Mount: ์ค์ผ์ค๋ฌ๊ฐ ๊ฐ์ ์ค๋ ๋๋ฅผ ์บ๋ฆฌ์ด ์ค๋ ๋์ ํ ๋นํ์ฌ ์คํ ์ํ๋ก ์ ํ
Execution: ์ฝ๋ ์คํ
Unmount (Yield): I/O ์์ ์ด๋
Sleep๋ฑ ๋ธ๋กํน์ด ๋ฐ์ํ๋ฉด, ๊ฐ์ ์ค๋ ๋๋ ์บ๋ฆฌ์ด ์ค๋ ๋์์ ๋ด๋ ค์ ์ธ๋ง์ดํธ ์ํ๋ก ์ ํํ์ฌ๊น์ง์ ์คํ ์ํ๋ฅผ Heap ์์ญ์ ์ ์ฅ
Wait: ๊ฐ์ ์ค๋ ๋๊ฐ ์ฌ๋ ๋์ ์บ๋ฆฌ์ด ์ค๋ ๋๋ ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฒ๋ฆฌ
Remount: I/O๊ฐ ์๋ฃ๋๋ฉด ๋ค์ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๋ง์ดํธ๋์ด Heap์ ์ ์ฅํ๋ ์ํ๋ฅผ ๋ณต๊ตฌํ๊ณ ์คํ ์ฌ๊ฐ
์ปจํฐ๋ด์์ด์
(Continuation)
๊ฐ์ ์ค๋ ๋์ ํต์ฌ ๋งค์ปค๋์ฆ์ผ๋ก, ์คํ ์ค์ธ ์ง์ ์ ์ํ๋ฅผ ๋ณด์กดํ๊ณ ๋์ค์ ํด๋น ์ง์ ๋ถํฐ ์ฌ๊ฐํ ์ ์๊ฒ ํ๋ ๊ธฐ๋ฅ
JVM์ ์ธ๋ง์ดํธ ์์ ์ CPU ๋ ์ง์คํฐ์ ์คํ์ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ๋ณต์ฌํ๊ณ , ์ฌ๊ฐ ์์ ์ ๋ค์ ๋ณต๊ตฌ
ํ๋ซํผ ์ค๋ ๋์ ๊ฐ์ ์ค๋ ๋ ๋น๊ต
๊ด๋ฆฌ ์ฃผ์ฒด
OS ์ปค๋
JVM
๊ธฐ๋ณธ ์คํ ํฌ๊ธฐ
์ฝ 1MB (๊ณ ์ ์ )
์๋ฐฑ ๋ฐ์ดํธ ~ ์ KB (๊ฐ๋ณ์ )
์์ฑ ๋น์ฉ
๋งค์ฐ ๋์ (ํ๋ง ํ์)
๋งค์ฐ ๋ฎ์ (ํ์ ์ ์์ฑ)
์ปจํ ์คํธ ์ค์์นญ
OS ์ปค๋ ์ค์์นญ (๋ฌด๊ฑฐ์)
JVM ๋ด ์ค์์นญ (๊ฐ๋ฒผ์)
ํ์ฅ์ฑ
์์ฒ ๊ฐ ์์ค
์๋ฐฑ๋ง ๊ฐ ์์ค
๊ฐ์ ์ค๋ ๋ vs ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ(WebFlux) ์์ธ ๋น๊ต
๊ฐ์ ์ค๋ ๋์ ๋ฆฌ์กํฐ๋ธ ๋ชจ๋ธ์ ๋ชจ๋ ๋์ ์ฒ๋ฆฌ๋์ ๋ชฉ์ ์ผ๋ก ํ์ง๋ง, ๊ทผ๋ณธ์ ์ผ๋ก ๋ค๋ฅธ ์ฒ ํ๊ณผ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ์ ๊ฐ์ง๊ณ ์๋ค.
๋์ ๋ฉ์ปค๋์ฆ
์ปจํฐ๋ด์์ด์ ๋ฐ ๋ง์ดํธ ์ ๋ต ํ์ฉ
์ด๋ฒคํธ ๋ฃจํ ๋ฐ ์ฝ๋ฐฑ ๊ธฐ๋ฐ ์ฒ๋ฆฌ
I/O ์ฒ๋ฆฌ ๋ฐฉ์
๊ธฐ์กด ๋ธ๋กํน ์ฝ๋ ๋ฐฉ์
๋ ผ๋ธ๋กํน ๋งค์ปค๋์ฆ ํ์
๋ฐฐ์ (Backpressure)
๋ณ๋์ ์ ์ด ๋ฉ์ปค๋์ฆ์ด ์กด์ฌํ์ง ์์
๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ฆ ํ์ค์ ํตํ ๊ฐ๋ ฅํ ํ๋ฆ ์ ์ด
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ฐ ์ํ
์๋ฐฑ๋ง ๊ฐ ์์ฑ ์ ํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๊ธ์ฆํ๊ฑฐ๋ ThreadLocal ๋จ์ฉ ์ OOM ์ํ ์กด์ฌ
๊ณ ์ ๋ ์์ ์ค๋ ๋๋ง ์ฌ์ฉํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ผ์ ํ๊ณ ์์ธก ๊ฐ๋ฅ
์์ ํจ์จ์ฑ
์๋ฐฑ๋ง ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ ์ ์์ผ๋ ๊ฐ๋ณ ์ค๋ ๋์ ์ํ ์ ์ฅ ๋น์ฉ ๋ฐ์
์ ์ ์์ ์ค๋ ๋๋ก ๋๊ท๋ชจ ๋์ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๋ ๊ณ ๋ฐ๋ ํจ์จ์ฑ
์๋ฌ ํธ๋ค๋ง
ํ์ค์ ์ธ try-catch ๋ฐ ๋ช ๋ นํ ์์ธ ์ฒ๋ฆฌ ํ์ฉ
์ฐ์ฐ์ ์ฒด์ธ ๋ด ์ ์ฉ ํธ๋ค๋ฌ๋ฅผ ํตํ ๋น๋๊ธฐ ์์ธ ์ฒ๋ฆฌ
์ฃผ์ ์ฌ์ฉ ์ฌ๋ก
์ผ๋ฐ์ ์ธ CRUD API, JDBC ๊ธฐ๋ฐ ๋ ๊ฑฐ์ ์์คํ ์ ํ, ๋จ์ ๋ณ๋ ฌ ์์
์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ, ๊ฒ์ดํธ์จ์ด, ์ ๊ตํ ํ๋ฆ ์ ์ด / ๋ฐฐ์ ํ์ํ ์์คํ
์ฌ์ฉ ์ ์ฃผ์์ฌํญ
๊ฐ์ ์ค๋ ๋๋ ๊ธฐ์กด Thread API๋ฅผ ๊ณ์นํ์ง๋ง, ๋ด๋ถ ๋์ ๋ฐฉ์์ ์ฐจ์ด๋ก ์ธํด ๊ธฐ์กด์ ์ค๋ ๋ ์ฌ์ฉ ํจํด์ด ๊ทธ๋๋ก ์ ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
์ค๋ ๋ ํ ๋ฏธ์ฌ์ฉ
๊ฐ์ ์ค๋ ๋๋ ์ฌ์ฌ์ฉ์ ๋ชฉ์ ์ผ๋ก ์ค๊ณ๋์ง ์์
์์ฑ ๋น์ฉ์ด ๋งค์ฐ ์ ๋ ดํ๋ฏ๋ก
ExecutorService๋ฅผ ํตํด ํ๋งํ๊ธฐ๋ณด๋ค ์์ ๋ง๋ค ์ ์ค๋ ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ์ ๊ถ์ฅ
ํผ๋(Pinning) ํ์
synchronized๋ธ๋ก ๋ด์์ I/O ์์ ์ด ๋ฐ์ํ๋ฉด ๊ฐ์ ์ค๋ ๋๊ฐ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๊ณ ์ ๋์ด ์ธ๋ง์ดํธ๋์ง ์์์ด๋ก ์ธํด ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๋ค์ด ์คํ ๊ธฐํ๋ฅผ ์๋ ์ฑ๋ฅ ์ ํ ๋ฐ์
ํด๊ฒฐ์ฑ :
synchronized๋์ReentrantLock์ฌ์ฉํ์ฌ ํผ๋ ๋ฐฉ์ง
ThreadLocal ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
๊ฐ์ ์ค๋ ๋๊ฐ ์ธ๋ง์ดํธ๋ ๋
ThreadLocal์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ ํ์ผ๋ก ์ด๋ํ์ฌ ๊ด๋ฆฌ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ
ThreadLocal์ ์ ์ฅํ ๊ฒฝ์ฐ, ์๋ฐฑ๋ง ๊ฐ์ ๊ฐ์ ์ค๋ ๋๊ฐ ๋์์ ์กด์ฌํ๋ฉด ํ ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ํ์ ๋ฐ์ ๊ฐ๋ฅ๊ฐ์ ์ค๋ ๋ ํ๊ฒฝ์์๋
ThreadLocal์ฌ์ฉ์ ์ต์ํํ๊ฑฐ๋, ๊ฐ๋ฒผ์ด ๋ฐ์ดํฐ ์์ฃผ๋ก ๊ตฌ์ฑํ๋ ๊ฒ์ด ์ข์
์ฑ๋ฅ์ ์ธก๋ฉด์์์ ๊ณ ๋ ค์ฌํญ
์ฒ๋ฆฌ๋(Throughput) vs ์๋ต ์๋(Latency): ๊ฐ์ ์ค๋ ๋๋ ๊ฐ๋ณ ์์ ์ ์๋๋ฅผ ๋น ๋ฅด๊ฒ ๋ง๋๋ ๊ฒ์ด ์๋๋ผ, ๋จ์ ์๊ฐ๋น ์ฒ๋ฆฌํ ์ ์๋ ์์ ์ ์์ ๋๋ ค์ฃผ๋ ๋๊ตฌ
CPU Bound ์์ : ๋ณต์กํ ์ฐ์ฐ์ด ์ฃผ๋ฅผ ์ด๋ฃจ๋ ์์ ์์๋ ๊ฐ์ ์ค๋ ๋์ ์ด์ ์ด ์์ผ๋ฉฐ, ์คํ๋ ค ์ค์ผ์ค๋ง ์ค๋ฒํค๋๋ก ์ธํด ์ฑ๋ฅ์ด ํ๋ฝ ๊ฐ๋ฅ์ฑ ์กด์ฌ
I/O Bound ์์ : ๋๊ท๋ชจ ํธ๋ํฝ์ ์ฒ๋ฆฌํ๋ API ์๋ฒ๋ ๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์ ๋ฆฌ์์ค ํจ์จ์ฑ์ ๊ทน๋ํํ๋ ๋ฐ ์ต์
๊ฐ์ ์ค๋ ๋ ์์ฑ ๋ฐ ์คํ ์์
Java 21๋ถํฐ ์ถ๊ฐ๋ Executors.newVirtualThreadPerTaskExecutor()๋ฅผ ์ฌ์ฉํ๋ฉด, ์ ์ถ๋๋ ๋ชจ๋ ํ์คํฌ์ ๋ํด ์๋ก์ด ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ์ฌ ์คํํ๋ค.
ํ๋ ์์ํฌ ์ง์(Spring Boot 3.2+)
Spring Boot 3.2 ๋ฒ์ ๋ถํฐ๋ ๋ณต์กํ ์ค์ ์์ด ํ๋กํผํฐ ํ๋๋ก ๋ชจ๋ ์๋ธ๋ฆฟ ์ฒ๋ฆฌ ์ค๋ ๋๋ฅผ ๊ฐ์ ์ค๋ ๋๋ก ์ ํํ ์ ์๋ค.
Tomcat์ด๋ Jetty ๊ฐ์ ๋ด์ฅ ์น ์๋ฒ๊ฐ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ ์ฒ๋ฆฌ
๊ธฐ์กด์
@Async์ฒ๋ฆฌ๋ ์ค์ผ์ค๋ฌ ๋ฑ๋ ๊ฐ์ ์ค๋ ๋ ๊ธฐ๋ฐ์ผ๋ก ๋์
๊ฐ์ ์ค๋ ๋ ๊ธฐ๋ฐ Executor ์ฌ์ฉ
๊ฐ์ ์ค๋ ๋ ๋ฐฉ์ ์ฌ์ฉ ์, ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ(OOM)์ด๋ ์ฑ๋ฅ ์ ํ ์์ด ์์ ์ํํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ฐ์ ์ค๋ ๋ ์ง์ ์์ฑ (Thread Builder)
ํน์ ์์
ํ๋๋ฅผ ๊ฐ์ ์ค๋ ๋๋ก ์ฆ์ ์คํํ๊ณ ์ถ์ ๋๋ Thread.ofVirtual() ๋น๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ์์ฑํ ์ ์๋ค.
Last updated