TL;DR
μ΄λ² κΈμ ν΅μ¬μ μμ½νλ©΄ λ€μκ³Ό κ°λ€
- @Async μ?
- Spring μμ λΉλκΈ° μμ μ μ½κ² μ€νν μ μλλ‘ λμμ£Όλ κΈ°λ₯
- μ ThreadPoolTaskExecutor λ₯Ό λ±λ‘ν΄μΌ ν κΉ?
- Spring μ κΈ°λ³Έ λΉλκΈ° μ²λ¦¬ Executor λ λ§€λ² μλ‘μ΄ thread λ₯Ό μμ±
- ThreadPool μ μ΄μ©ν νμκ° μμ
- μ¬μ μ§μ
- Executor μ ThreadPoolExecutor
- Spring μ TaskExecutor
- ThreadPoolExecutor μ΄ν΄νκΈ°
- μ ννλ ThreadPoolExecutor μμμ μ΄λ€ λ‘μ§μ μν΄ μλ‘μ΄ thread λ₯Ό λ§λλμ§ μμμΌ ν¨
- μ€μ μ λ°λΌ single thread μ²λΌ λμν μ μμ
- μ μ ν ThreadPoolTaskExecutor μ μ€μ κ° μ°ΎκΈ°
- μ°μ°μ μ’ λ₯μ λ°λΌ CPU bound / IO bound λ‘ κ΅¬λΆ
- Java Concurrency in Practice μμ μ μνλ κ³μ°λ²
- μ€μν 건 μ§μ μ±λ₯ ν μ€νΈλ₯Ό ν΅ν΄ νμΈνκΈ°
Spring μμ @Async
μ΄λ
Έν
μ΄μ
Spring μΌλ‘ Application μ κ°λ°νλ€ λ³΄λ©΄ λΉλκΈ° task λ₯Ό μ€νν΄μΌ ν μΌμ΄ μ’ μ’ μλ€.
λ€μκ³Ό κ°μ΄ @EnableAsync
μ @Async
λ₯Ό μ΄μ©ν΄μ Spring μμ λΉλκΈ° task λ₯Ό λ§μ΄ μ²λ¦¬ ν κ²μ΄λ€.
λ€λ₯Έ 보ν΅μ AoP λ Spring abstraction μ μ¬μ©λ²κ³Ό λΉμ·νκ², bean μΌλ‘ λ±λ‘λ ν΄λμ€μ μ΄λ€ λ©μλκ° @Async
μ΄λ
Έν
μ΄μ
μΌλ‘ decorate λμλ€λ©΄ Spring μ ν΄λΉ method λ₯Ό proxy λ₯Ό μ΄μ©νμ¬ μμ² thread μ λ³κ°μ thread μμ ν΄λΉ λ©μλλ₯Ό μνν μ μκ² νλ€.
μ ThreadPoolTaskExecutor bean μ λ±λ‘ν΄μΌ ν κΉ?
κ·ΈλΌ λ³Έλ‘ μΌλ‘ λ€μ΄κ°μ, @Async
λ₯Ό μ¬μ©ν λμλ μ ThreadPoolTaskExecutor
λ₯Ό μ΄μ©ν΄μΌ ν κΉ?
κ·Έ μ΄μ λ @EnableAsync
μ΄λ
Έν
μ΄μ
μμ μ½κ² νμΈ ν μ μλ€.
- κΈ°λ³Έμ μΌλ‘ @EnableAsync μ΄λ Έν μ΄μ μ μ¬μ©ν κ²½μ° TaskExecutor νμ μ bean μ μ°Ύμ
- λ§μ½ user κ° λ±λ‘ν custom bean μ΄ μ‘΄μ¬νμ§ μμ κ²½μ° SimpleAsyncTaskExecutor λ₯Ό μ¬μ©ν¨
- SimpleAsyncTaskExecutor μμλ thread λ₯Ό reuse νμ§ μμ
μ¦, λΉλκΈ° task κ° λ°μν λλ§λ€ κ³μν΄μ thread λ₯Ό μμ±νκΈ° λλ¬Έμ΄λ€.
thread λ₯Ό μμ±νλ μμ
μ λ§€μ° λΉμΌ μμ
μ΄λΌλ μ¬μ€μ λ§€μ° μ λͺ
νλ°, μ°λ¦¬κ° ThreadPool μ μ¬μ©νκ² λ€κ³ λͺ
μνμ§ μμΌλ©΄ Spring μ κΈ°λ³Έμ μΌλ‘ SimpleAsyncTaskExecutor
λ₯Ό λΉλκΈ° task executor μ κΈ°λ³Έ ꡬνμ²΄λ‘ λ±λ‘ νκΈ° λλ¬Έμ μ ν리μΌμ΄μ
μ μ±λ₯ νλ½μ΄ λ°μ ν μ μλ€.
μ ThreadPool μ μ¬μ©ν΄μΌ νλκ°μ λν μ΄μΌκΈ°λ νμ§ μκ² λ€. μ΄μ κ° κΆκΈνλ€λ©΄ 10 λΆ ν μ½ν‘ ThreadPool - μ°ν μ½ youtube μμ νμΈν μ μλ€.
λͺ¨λ μμ μμ thraedPool μ μ¬μ©νλ κ²μ΄ νμ μ’μ μ±λ₯μ λ΄μ§λ μμ§λ§ (CPU bound μμ κ³Ό κ°μ) μ°λ¦¬κ° λ§λλ λλΆλΆμ application μ IO bound κ° λ§κΈ° λλ¬Έμ λΉλκΈ° μ²λ¦¬λ threadPool μ μ΄μ©νλ νΈμ΄ μ’λ€
ThreadPoolTaskExecutor μ΄μΌκΈ° νκΈ° μ μ μ¬μ μ§μ
κ·Έ μ μ, 짧μ μ¬μ μ§μμ μ΄μΌκΈ° ν΄λ³΄λ©° java μ Executor
μ ExecutorService
κ·Έλ¦¬κ³ Spring μ TaskExecutor
μ λν΄μ μμ보μ
μ¬μ μ§μ 1. java μ Executor μ ExecutorService
java5 λ²μ μ΄ μΆμλ λ java.util.concurrent
ν¨ν€μ§ threading, scheduling κ³Ό κ°μ λΉλκΈ° μμ
μ λ μ½κ² ν μ μλλ‘ Executor
λΌλ μΈν°νμ΄μ€κ° μΆκ°λμλ€.
- κ°λ°μλ λͺ
μμ μΌλ‘
new Thread
λ₯Ό ν΅ν΄ μ€λ λλ₯Ό μμ±νμ§ μμλ λ¨ - runnable μμ μ μ½κ² μ€νν μ μλλ‘ λμμ€
- μ€λ λ μλͺ μ£ΌκΈ°λ₯Ό μ ν리μΌμ΄μ κ°λ°μλ€μ΄ μ½κ² κ΄λ¦¬ν μ μλλ‘ ν¨
ExecutorService
λ Executor
μΈν°νμ΄μ€λ₯Ό νμ₯νμ¬ λΉλκΈ° task μ μ€νμ λ μ½κ³ νμ₯μ± μλλ‘ κ΄λ¦¬νλ νμ₯ μΈν°νμ΄μ€μ΄λ€.
- task μ€νμ΄ λμ± κ°νΈν΄μ§
- Executors λΌλ static factory class λ₯Ό ν΅ν΄ μ¬λ¬ νμ
μ ExecutorService μΈμ€ν΄μ€λ₯Ό μμ±ν μ μλλ‘ ν¨
- fixedThreadPool, singleThread λ±λ± μ½κ² executor λ₯Ό μμ±ν μ μμ
μ΄ λ ν΄λμ€λ₯Ό μ μ΄μ©νλ€λ©΄ λ€μκ³Ό κ°μ΄ μ½κ² threading μ ν μ μκ² λλ€
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
System.out.println("λΉλκΈ° μμ
μ€ν");
});
executor.shutdown();
}
}
μ¬μ μ§μ 2. Spring μ TaskExecutor
Spring Core docs μ TaskExecution μμ μ μ μμ§λ§ Spring μ TaskExecutor λ₯Ό ν΅ν΄ λΉλκΈ° μμ μ λν μΆμνλ₯Ό μ 곡νλ€.
TaskExecutor λ μμ μ€λͺ
ν java μ Executor λ₯Ό wrapping ν μΈν°νμ΄μ€λ‘ java.util.concurrent.Executor
λ₯Ό μμνλ€
Spring μμλ μ¬λ¬ TaskExecutor
μ ꡬν체λ₯Ό μ 곡νλλ° λνμ μΌλ‘ μ°λ¦¬κ° λ΄€λ SimpleAsyncTaskExecutor
μ μμΌλ‘ μ΄μΌκΈ° ν ThreadPoolTaskExecutor
κ° μλ€.
ThreadPoolTaskExecutor λ?
ThreadPoolTaskExecutor λ java μ ThreadPoolExecutor.java λ₯Ό wrapping ν Spring μ Executor μ΄λ€.
ThreadPoolTaskExecutor
λ₯Ό Async task λ₯Ό μ²λ¦¬ν Bean μΌλ‘ λ±λ‘νκΈ° μν΄μλ λμ λ°©μμ μ νν μ΄ν΄ν΄μΌ νλ€
ThreadPoolTaskExecutor λ μ΄λ»κ² μ€λ λλ₯Ό μμ±νλκ°
μμ±μ λν λμ λ°©μμ μ΄ν΄ν΄μΌ νλ μ΄μ λ μ°λ¦¬κ° λ±λ‘νλ bean μ€μ μ΄ μ§μ μ μΌλ‘ μ±λ₯μ μν₯μ λ―ΈμΉκΈ° λλ¬Έμ΄λ€.
μ΄μ λ ThreadPoolTaskExecutor
κ° Thread λ₯Ό μμ±νλ λ°©μμ μλλ°, μ΄λ₯Ό μ΄ν΄νκΈ° μν΄μλ λ€μ 4κ°μ§ κ°λ
λ§ κΈ°μ΅νμ
- core pool size
- max pool size
- queue capacity (waiting queue)
- activeThreadCount
ThreadPoolTaskExecutor
λ μμ 3κ°μ§ μ 보λ₯Ό κ°μ§κ³ bound μ λ°λΌ μλμΌλ‘ ν ν¬κΈ°(μ€λ λμ μ)λ₯Ό μ‘°μ νλ€.
μ΄λ€ μμλ‘ μμ±μ΄ λλμ§ μμ보μ.
- μ΄κΈ°μλ corePoolSize λ§νΌ μ€λ λλ₯Ό μμ±νλ€.
- μ κ·λ‘ μμ²μ΄ λ€μ΄ μμ λ, corePoolSize λ§νΌ μ€λ λκ° ν λΉλλ©΄ queue μ μμ²μ λκΈ°μν¨λ€
- queue κ° κ½ μ°¨λ©΄ μ κ·λ‘ μ€λ λλ₯Ό μμ±νλ€.
- 3λ² κ³Όμ μ maxPoolSize λ§νΌ μ€λ λλ₯Ό μμ±λ λ κΉμ§ λ°λ³΅νλ€
- λ§μ½ maxPoolSize λ§νΌ μ€λ λλ₯Ό μμ±νκ³ corePoolSize κ° κ½ μ°Όλ€λ©΄ μμ²μ reject νλ€
μμ μμλ₯Ό κ·Έλ¦ΌμΌλ‘ λμν νλ€λ©΄ λ€μκ³Ό κ°λ€.
μ¬κΈ°μ μ€μν μ¬μ€μ activeThreadCount
κ° maxPoolSize
λ§νΌ ν λΉλκ³ waiting queue
κ° κ½ μ°¬λ€λ©΄ λͺ¨λ μμ²μ Reject νλ€λ κ²μ΄λ€.
ThreadPoolTaskExecutor κ° μμ²μ Reject ν λ?
μμ λ¬Έμ₯μ μ½μμΌλ‘ νννλ€λ©΄ activeThreadCount == maxPoolSize && queue is full
λΌλ©΄ task μ€ν μμ²μ΄ κ±°λΆλλ€.
μ΄λ, κ±°λΆλ μμ²μ RejectExecutionHandler.java μ μν΄μ handling λ μ μλ€. μ¬κΈ°μ RejectionHandlingPolicy λ₯Ό μ΄λ»κ² κ°μ Έκ°μΌ νλμ§λ λ§€μ° μ€μνλ―λ‘ μμΈν λ΄μ©μ μμ docs λ₯Ό ν΅ν΄ νμΈνμ.
μμ μ€λ λ μμ± λ°©μμ μ΄ν΄νμ§ λͺ»ν μ± ThreadPool λ§ μ¬μ©νκ² λ€κ³ ThreadPoolTaskExecutor
bean μ λ€μκ³Ό κ°μ΄ μ€μ νμ¬ bean μ λ±λ‘ν μ½λλ₯Ό νμλ λ§μ΄ λ΄ μλ€.
@Primary
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setQueueCapacity(1024); // waiting pool size
executor.setMaxPoolSize(10);
return executor;
}
μ΄λ° μ€μ μ μΆκ°ν κ°λ°μμ μλλ μλ§λ μμ²μ΄ reject λλ κ² λ³΄λ€ queue μμ waiting νλ νΈμ΄ λ«λ€
λΌκ³ μκ°νμ ν
λ°,
μ€μ λ‘λ single thread λ‘ μ²λ¦¬λ κ²μ΄κ³ multi thread κ° λμνλ €λ©΄ 1024 κ° μ΄μμ΄ μμΌ λ λ²μ§Έ μ€λ λκ° μμ±λ κ²μ΄λ€.
κ·ΈλΌ μ μ ν ThreadPoolTaskExecutor μ μ€μ κ°μ?
μ μ ν ThreadPool μ μ€μ κ°μ λ»ν μ΄μΌκΈ°μ§λ§ νκ²½κ³Ό μ»΄ν¨ν μμ§μ λ°λΌ λ€λ₯΄λ€.
νμ§λ§ λͺκ°μ§ νμ΄ μ‘΄μ¬νλλ°, λ°λ‘ λ€μ 2κ°μ§λ₯Ό κ³ λ €νλ©΄ μ½κ² μ κ·Όν μ μλ€.
- μ°μ°μ μ’ λ₯μ λ°λΌ
- CPU μ½μ΄μ λ°λΌ
μ μ μ€λ λ ꡬνκΈ° - 1. μ°μ° μ’ λ₯ νμ νκΈ°
μ°μ°μ μ’ λ₯μ λ°λΌ μ€λ λ νμ ν¬κΈ°κ° μ»€μΌ νλμ§ μμμΌ νλμ§ νλ¨ ν μ μλ€.
- CPU Bouond μ°μ°
- CPU λ₯Ό νμ©ν μ°μ° μμ
- λκΈ°μκ°μ΄ κ±°μ 0μ μλ ΄νλ―λ‘ μ€λ λ νμ΄ μλ€λ©΄ Context Switching μ΄ μμ£Ό λ°μν΄ λΉν¨μ¨ λ°μ
- IO Bound μ°μ°
- HTTP, File κ³Ό κ°μ IO μ°μ° μμ
- λ³΄ν΅ WAITING TIME μ΄ κΈΈκΈ° λλ¬Έμ μ€λ λ νμ ν¬κΈ°κ° ν΄ λ ν¨κ³Όμ μ
μ μ μ€λ λ ꡬνκΈ° - 2. CPU μ½μ΄ μ νμ νκΈ°
ν¨μ¨μ μΈ μ°μ°μ μν΄μλ CPU μ Free time μ μ μ ν μΌμ μν€λ κ²μ΄ μ€μνλ€.
νλμ μ½μ΄μμ λ³΄ν΅ νλμ μ€λ λλ₯Ό μ€ν μν€λ―λ‘ μ μ μ€λ λμ μλ μ½μ΄μ μμ λΉλ‘νλ€.
μ΄λ¬ν 곡μμ΄ μμ§λ§ λ©ν° μ€λ λ νμ΄ κ³ λ €λμ§ μμκ³ , μ΄λ₯Ό κ³ λ €ν μ¬λ¬ μμμ΄ μ‘΄μ¬νλ μ μ μ€λ λμ κ°μλ₯Ό ꡬνλ κ°μ₯ ν¨κ³Όμ μΈ λ°©λ²μ stress test λ±μ ν΅ν΄ μ§μ μλ₯Ό μ‘°μ νλ κ²μ λͺ μ¬νμ.
μ μ ν ThreadPool μ μ€μ κ°μ μ΄μμ μΈ μ€λ λ ν ν¬κΈ°μ λνμ¬ - code-lab1.tistory.com μμ μ€λͺ μ μ ν΄μ£Όκ³ μμΌλ μ°Έκ³ νλ κ²λ μ’μ κ² κ°λ€.
λκΈ