π οΈBackend/π³Spring
[Spring Framework] μ€νλ§ λΉλκΈ° μ²λ¦¬ λ°©λ²
junbin2
2025. 7. 25. 04:01
β 1. λΉλκΈ°(Asynchronous) λ?
1. ν΄λΌμ΄μΈνΈ μμ²
2. μ컀 μ€λ λ ν΄λΌμ΄μΈνΈ μμ² μ²λ¦¬
3. λμ μ€ λΉλκΈ° λ‘μ§ λ°κ²¬
4. μ컀 μ€λ λλ₯Ό νλ λ λ§λ€μ΄μ λΉλκΈ° λ‘μ§μ μ²λ¦¬
5. μμ² μ²λ¦¬ λ° λΉλκΈ° μ²λ¦¬ μ€λ λ λκ°κ° λμκ°κ² λ¨.
6. μ€μΌμ€λ¬μ μν΄ λ°λ‘ λμμ λμμνκ² λ¨.
- μ΄λ€ μμ μ μμ²ν ν κ·Έ μμ μ μλ£ μ¬λΆλ₯Ό κΈ°λ€λ¦¬μ§ μκ³ λ€μ μμ μ λ°λ‘ μννλ λ°©μμ μλ―Ένλ€.
- λ³΄ν΅ κ΅¬νμ μμ² νλ μ€λ λμμ λΆκΈ°λμ΄ λμμ λ€λ₯Έ μμ λ μ²λ¦¬νλ κ³Όμ μ΄λΌκ³ λ³Ό μ μμ.
β 2. Spring μμ λΉλκΈ°(Asynchronous) μ²λ¦¬
β
@EnableAsyncκ° νλ μΌ μμ½ ( μ λν
μ΄μ
μ¬μ©μ λ΄λΆ λμ )
AsyncAnnotationBeanPostProcessor λ±λ‘
→ @Async μ λν
μ΄μ
μ΄ λΆμ λ©μλλ₯Ό κ°μ§ν΄μ
→ ν΄λΉ λ©μλλ₯Ό **νλ‘μ(proxy)**λ‘ κ°μΈκ³ , λΉλκΈ° μ€νλλλ‘ μ€μ
TaskExecutor (μ€λ λ ν) μ€μ
→ @Async λ©μλκ° μ€νλ λ μ¬μ©ν Executorλ₯Ό κ²°μ ν¨
→ TaskExecutorλΌλ λΉμ΄ λ±λ‘λμ΄ μμΌλ©΄ κ·Έκ²μ μ¬μ©
→ μλ€λ©΄, κΈ°λ³Έ SimpleAsyncTaskExecutorλ₯Ό μ¬μ© (λΉμΆμ²: μ€λ λ μ¬μ¬μ© X)
λΉλκΈ° νΈμΆ νλ¦ κ΄λ¦¬
→ νλ‘μκ° @Async λ©μλλ₯Ό νΈμΆν λ,
→ ν΄λΉ λ‘μ§μ λ€λ₯Έ μ€λ λμμ μ€νλλλ‘ λΆκΈ° μ²λ¦¬
- μ€νλ§μμλ κΈ°λ³Έμ μΌλ‘ λΉλκΈ° μ²λ¦¬λ₯Ό μν μ½λλ₯Ό μ 곡μ ν΄μ€λ€.
- @EnableAsync μ λν μ΄μ μ€μ μ νκ² λλ©΄, μ€νλ§ λ΄λΆμ μΌλ‘ λΉλκΈ° μ²λ¦¬μ νμν ν΅μ¬ ꡬμ±μμλ€μ μλμΌλ‘ λΉμΌλ‘ λ±λ‘νκ³ νμ±νλ₯Ό ν΄μ€λ€.
- μ μν΄λ @Async μ λν μ΄μ μ΄ νΈμΆμ΄ λ λ λ§λ€ ν΄λΉ λ©μλλ₯Ό λΉλκΈ°λ‘ μ²λ¦¬λ₯Ό ν΄μ€λ€.
- μ¦, μ€λ λλ₯Ό μλ‘ λ§λ€μ΄μ μ²λ¦¬λ₯Ό ν΄μ€λ€λ μλ―Έμ΄λ€.
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor taskExecutor() { // μ€λ λ ν μ§μ μ μνλ λ©μλ
// μ€νλ§μμ μ 곡νλ μ€λ λ ν ꡬν체
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // νμ μ μ§λλ μ΅μ μ€λ λ μ
executor.setMaxPoolSize(10); // μ΅λ μ€λ λ μ μ ν
executor.setQueueCapacity(100); // λΉλκΈ° μμ
μμ² λκΈ° ν ν¬κΈ°
executor.setThreadNamePrefix("AsyncExecutor-"); // μ€λ λ μ΄λ¦ prefix μ§μ
executor.initialize(); // μ€λ λ ν μ΄κΈ°ν λ©μλ
return executor;
}
}
- Async μ€μ νμΌμ λ³΄ν΅ μμ μ½λμ κ°μ΄ μ€μ μ νκ² λλ€. ν΄λΉ μ€μ Bean μ @Async μμ μ¬μ©ν μ€λ λ ν(TaskExecutor) μ μ§μ μ μνλ κ³³μ΄λ€.
- setXorePoolSize(5) λ©μλλ νμ μ μ§λλ μ΅μ μ€λ λ μλ₯Ό set ν μ μλ setter μ΄λ€. μ½κ²λ§ν΄, λΉλκΈ° μμ μ΄ μμ΄λ 5κ°μ μ€λ λλ₯Ό κΈ°λ³Έμ μΌλ‘ μ μ§νλ©°, μ²μμ μ¬κΈ°κΉμ§μ μ€λ λ μλ§νΌλ§ μμ±μ΄ λλ€λ μλ―Έμ΄λ€.
- setMaxPoolSize(10) λ©μλλ μ΅λ μ€λ λ μ μ νμ μλ―Ένλ©°, νκ° κ°λ μ°¨κ³ λ λ§μ μμ²μ΄ λ€μ΄μ€λ©΄, corePoolSize μ΄μμΌλ‘λ μ€λ λλ₯Ό νμ₯ν΄μ μ²λ¦¬λ₯Ό νλ€. νμ§λ§ μ΄κ²λ μ΅λλ κΈ°μ¬ν΄λ κ² κΉμ§ κ°λ₯νλ€.
- setQueueCapaciry(100) λ©μλλ λΉλκΈ° μμ μμ²μ΄ λ€μ΄μ¬ λ λκΈ° ν μ μλ νμ ν¬κΈ°λ₯Ό μλ―Ένλ€. corePoolSize λ§νΌ μ€λ λκ° λ€ μ°Όμ λλ μ΄ νμ μμ μ λ£μ΄μ λκΈ°λ₯Ό μν¨λ€. μ½κ²λ§ν΄, κΈ°μ‘΄ μ€λ λμ μ¬μ©μ΄ λ€ λκ³ λ°λ©μ΄ λλ©΄ μ¬κΈ°μ κΊΌλ΄λ€κ° μ΄λ€λ μλ―Έμ΄λ€. λ§μ½ νκ° κ½μ°¨μ νκ³μ λλ¬νκ² λλ©΄ μ΄νμ μ μ₯μ RejectedExecutionException μμΈκ° λ°μνκ² λλ€. μ΄λ κ² λλ©΄, μμ²μ 보λΏμ§λ§, μ무 μΌλ μ μΌμ΄λλ νμμ΄ λ°μ ν μ μμ. μ¦, μμ²μ΄ μ¦λ° ν μ μμ.
- initialize() ν΄λΉ λ©μλλ μ€λ λ νμ μ΄κΈ°ννλ λ©μλλ‘ λ°λμ νΈμΆν΄μΌ μ€μ λ‘ μ¬μ©μ΄ κ°λ₯νλ€.
(1) μ΄νμ νλ¦ μμ½
| 1 | ν΄λΌμ΄μΈνΈκ° HTTP μμ² |
| 2 | Controller → Service κ³μΈ΅μμ @Async λ©μλ νΈμΆ |
| 3 | Springμ΄ taskExecutor()λ‘ μ μλ μ€λ λ νμμ μ컀 μ€λ λ κΊΌλ |
| 4 | λΉλκΈ° λ©μλλ μ΄ μ컀 μ€λ λμμ μ€νλ¨ |
| 5 | κΈ°μ‘΄ μμ² μ€λ λλ λ°λ‘ ν΄λΌμ΄μΈνΈμκ² μλ΅ |
(2) Async μ€ν μμ
π @Asyncμ μ€ν μμ (μμ½)
1. μ¬μ©μκ° λΉλκΈ° λ©μλ νΈμΆ
2. corePoolSize λ§νΌ μ€λ λλ‘ μ€ν (μ¦μ μ²λ¦¬)
3. κ·Έ μ΄μμ queueCapacityλ§νΌ νμ μ μ₯ (λκΈ° μν)
4. νλ κ½ μ°¨λ©΄ → maxPoolSizeλ§νΌ μ€λ λλ₯Ό μΆκ° μμ±
5. λͺ¨λ νκ³ λ€ μ°Όμ λ → RejectedExecutionException λ°μ
β 3. Async λ©λͺ¨λ¦¬ κΈ°λ° Queueμ νλ°μ± λ° μμ λλ½ λ¬Έμ
- @Async κ° μ¬μ©νλ ThreadPoolTaskExecutor λ΄λΆμλ μμ μ 보κ΄νλ ν(Queue) κ° μ‘΄μ¬ν¨.
- μ΄ νλ μλ° μ ν리μΌμ΄μ λ©λͺ¨λ¦¬ μμμλ§ μ μ§λλ μλ£κ΅¬μ‘°μ΄λ€ 보λ, JVM νλ‘μΈμ€κ° μ’ λ£λκ±°λ μ¬μμ λλ©΄ ν μμ μλ μμ μ λ³΄κ° λͺ¨λ μ¬λΌμ§ μ μλ€. μ¦, λ©λͺ¨λ¦¬ λ¬Έμ , μλ² μ₯μ , μ¬λ°°ν¬ μμ λΉλκΈ° μμ μ΄ λ μκ° μνμ΄ μλ€λ μλ―Έμ΄λ€.
- μ΄λ κ² λλ€λ©΄ ν΄λΌμ΄μΈνΈμ μ€μν μμ²μ΄ λ λΌκ°λ λ¬Έμ κ° λ°μ ν μ μκ² λλ€.
(1) μ΄κ² λ¬Έμ μΈ μ΄μ
- λΉλκΈ° μμ μλ μ£Όλ‘ μ€μν μμ μΈ μ΄λ©μΌ μ μ‘, μλ¦Ό, κ²°μ νμ²λ¦¬ λ±μ μ²λ¦¬ νλλ° μ¬μ©μ νλλ°, μ΄ μμ μ΄ λλ½λλ©΄ μλΉμ€ μ λ’°μ±μ μ§μ μ μΈ μ μν₯μ μ£ΌκΈ° λλ¬Έμ΄λ€.
β 4. Queueμ νλ°μ± λ° μμ λλ½ λ¬Έμ ν΄κ²° λ°©μ
(1) μ€λ λν λͺ¨λν°λ§
- ν μ¬μ΄μ¦λ₯Ό λ무 μκ² νλ©΄ μμ² νκ³λ₯Ό λ²μ΄λ λ RejectedExecutionException λ°μ
- ν μ¬μ΄μ¦λ₯Ό λ무 ν¬κ² μ€μ νλ©΄ λ©λͺ¨λ¦¬ μ¬μ©λ μ¦κ°, μμ μ§μ° κ°λ₯μ±μ΄ μ¦κ°ν¨.
- ThreadPoolWaskExecutor μ ν ν¬κΈ°, νμ± μ€λ λ μ, μλ£ μμ μ λ± νμ¬ μνλ₯Ό Spring μ Actuator λ JMX, Prometheus + Grafana κ°μ μ€μκ° λͺ¨λν°λ§ λꡬλ₯Ό νμ©ν΄μ λͺ¨λν°λ§μ ν μ μλ€.
- μ΄λ¬ν μ€μκ° λͺ¨λν°λ§μ ν΅ν΄ νκ° μ¬μ©μμ μ¦κ°λ‘ μΈν΄ νκ° κ°λμ°¨λ νμμ λ°κ²¬ ν μ μμΌλ©°, μ€λ λ μλ₯Ό λ리거λ μλ² μμμ μΆκ°ν¨μΌλ‘μ¨ λ¬Έμ λ₯Ό ν΄κ²° ν μ μλ€.
- μ¦, ν΄κ²°μ μν΄μλ λ‘κ·Έλ λͺ¨λν°λ§μ ν΅ν΄ ν ν¬κΈ°λ₯Ό μ μ ν μμ€μΌλ‘ μ€μ νκ±°λ νλνλ κ²μ΄ μ’μ.
(2) κ±°μ μ μ± (RejectedExecutionHandler) μ€μ
- μμ μμ²μ΄ λ무 λ§μ νμ μ€λ λκ° λ€ μ°Όμ λ λ‘κ·Έλ₯Ό λ¨κΈ°κ³ λ²λ¦¬λ μ μ± λ± μ μ ν λ°©μ΄ λ‘μ§μ λλ λ°©μμ΄λ€.
- νμ§λ§, μ΄ λ°©μμ κ·Όλ³Έμ μΈ λ¬Έμ ν΄κ²°μ΄λΌκΈ° λ³΄λ¨ μ¦μ μνλ μμ λμμ κ°κΉμ΄ λ°©μμ΄λ€.
(3) MQ(Message Queue) μ¬μ©
- MQ λ λΉλκΈ° μμ μ΄ μμ±μ΄ λλ©΄ ν΄λΉ μμ μ λ©μμ§λ‘ λ³΄κ³ , Queue μ μ μ₯μ νλ λ°©μμ΄λ€.
- ν΄λΉ MQ μ μ’ λ₯λ λνμ μΌλ‘ RabbitMQ, Kafka λ κ°μ§κ° μλ€.
- λ MQ λ λ©μμ§λ₯Ό λμ€ν¬ κΈ°λ° νμ μ μ₯μ νκΈ° λλ¬Έμ, κΈ°μ‘΄ μΈλ©λͺ¨λ¦¬ λΉλκΈ° μμ μ΄ μ¬λΌμ§λ λ¬Έμ λ₯Ό ν΄κ²°ν΄μ€λ€.
- λ©μμ§κ° λμ€ν¬μ μ μ₯λμ΄ μλ² μ₯μ μλ μμ μμ€μ΄ μλ λ΄κ΅¬μ±μ 보μ₯νλ€.
- μλΉμ μ μ‘°μ λ‘ λΆν λΆμ° λ° μ€μΌμΌ μμμ΄ κ°λ₯ μ¦, μ²λ¦¬λ μ‘°μ μ΄ κ°λ₯νλ€λ μλ―Έμ΄λ€.
- μΈλΆμ λΆλ¦¬λ ν μμ€ν μΌλ‘ μμ μ μ΄κ³ μ μ°ν λΉλκΈ° μ²λ¦¬λ₯Ό κ°λ₯νκ² λμμ€.
- μ€ν¨ν λ©μμ§λ₯Ό λ³λ νλ‘ λ³΄λ΄ μ¬μ²λ¦¬ κ°λ₯νκ² λμμ€.
- μ¬λ¬ μλ²κ° λ©μμ§λ₯Ό λλ μ²λ¦¬κ° κ°λ₯ν¨. μ¦, λΆμ° νκ²½μ μ§μν΄μ€λ€λ μλ―Έμ. λ§€μ° μ’μ μ₯μ μΈλ―..
β 5. μ 리
- @Asyncλ λ΄λΆμ μΌλ‘ μ€λ λν(ThreadPoolTaskExecutor) μ μ΄μ©ν΄ λΉλκΈ° μμ μ μ€ννλ€.
- κ°λ¨νκ³ μμ κ·λͺ¨ λ΄λΆ λΉλκΈ° μμ μ΄λΌλ©΄ @Async κ° λΉ λ₯΄κ³ κ°νΈνμ§λ§ μμ μ±, νμ₯μ±, λΆμ°μ²λ¦¬κ° νμνκ±°λ μ₯μ μμλ λ©μμ§ μ μ€μ λ§μμΌ νλ€λ©΄ MQλ₯Ό μ¬μ©νλκ² ν¨μ¬ λ«λ€κ³ νλ¨μ΄ λ¨.