-
SpringBoot에서 여러 요청을 동시에 처리하는 방법개발/Spring(boot) 2025. 3. 23. 23:26
Thread Pool에 대해 찾아보던 도중 좋은 강의가 있어 강의 내용에 대해 내가 이해한 방식대로 작성해 보고자 한다.
참고한 강의는 우아한테크코스의 강의로 아래 링크에서 확인할 수 있다.
https://www.youtube.com/watch?v=um4rYmQIeRE
Spring Boot 애플리케이션은 기본적으로 내장 서블릿 컨테이너(Tomcat, Jetty ..)를 사용하며,
이 서버들은 내부적으로 Thread Pool을 활용하여 요청을 처리한다.
따라서 Thread Pool 관련 설정값을 잘 조정해야 어플리케이션을 원할하게 운영할 수 있다.
이번 글에서는 아래 내용에 대해 작성해보고자 한다.
1. Program, Process, Thread?
2, Thread Pool?
3. Java의 Thread Pool
4. Web Server(Tomcat)
5. Thread Pool을 활용해 원할한 Springboot 어플리케이션 운영 방법
6. Coroutine과 Thread
1. Program, Process, Thread?
Program : 어떤 목적을 달성하기 위해 컴퓨터의 동작들을 하나로 모아 놓은 것
Process : 컴퓨터가 현재 실행중인 프로그램(program in execution)
Thread : 프로세스 내에서 실행 흐름을 나타내는 최소 실행 단위(Unit of Excution)
하나의 CPU 코어가 시간 분할 방식(time-slicing)을 통해 여러 스레드를 순차적으로 실행
프로세스 작업을 쓰레드 단위로 나눠서 실행 가능하고, 이를 CPU Core가 처리
=> Thread를 사용함으로서 하나의 프로세스의 여러 작업을 동시에 실행 가능
실행중인 Process를 단순 Thread만 사용하여 여러 작업을 실행시킨다면 효율적일까? -> X
아래 두 가지 문제 발생
1. 스레드의 큰 생성 비용 문제로 인한 요청-응답 대기시간 증가(Java에서)
1) Java의 경우 One-to-One Threading-Model로 Thread 생성(OS Level Thread와 1:1 매핑)
2) User Thread(Process의 Thread) 생성 시 OS Thread(OS Level Thread)와 연결 필요
3) 새로운 Thread를 생성할 때 마다 OS Kernel 작업 필요(생성 비용이 높음)
4) 따라서 작업 요청이 들어올 때 마다 Thread를 생성하면 최종적인 요청 처리 시간 증가(비효율)
2. Thread가 많아졌을 때의 생기는 문제
1) Process의 처리 속도 < 요청의 수인 경우
2) 새로운 Thread가 계속 생성
3) Thread 수가 증가함에 따라 메모리 사용량 증가, Context-Switching 발생 빈도 증가
4) 3번에 따른 메모리 문제, CPU 오버헤드 문제 발생
위 문제에 대한 해결 방안인 Thread Pool에 대해 작성해보겠다.
2. Thread Pool?
사용할 수 있는 Thread 수를 제한하는 시스템으로 Thread Pool을 활용한다면 위 두개의 문제를 아래와 같은 방법으로 해결할 수 있다.
스레드의 큰 생성 비용 문제로 인한 요청-응답 대기시간 증가
-> 미리 만들어둔 Thread를 재사용하므로 새로운 Thread 생성 비용 절감
Thread가 많아졌을 때의 메모리, CPU 오버헤드 문제
-> 사용할 Thread 수를 제한하므로 두 문제 방지 가능
그러면 Thread Pool에 대해 작성해보겠다.
1. Thread Pool의 구성 요소
1) Thread Pool 내의 Thread
2) Work Queue - 작업 큐
2. Thread Pool이 작업을 처리하는 방법
1) Thread Pool에 작업 처리 요청
2) 작업 큐에 작업이 쌓임
3) Thread Pool 내의 Thread들이 작업 큐에 있는 작업을 빼서 처리
3. Thread Pool의 특징
1) 정해진 양 만큼의 쓰레드를 사용
2) 한번 사용된 쓰레드가 작업이 끝난 뒤 재사용
따라서 여러 개의 작업을 동시에 안정적으로 처리하고 싶을 때 Thread Pool은 효과적이다.
3. Java의 Thread Pool
Java에서는 ThreadPoolExecutor 클래스를 이용해 Thread를 구현하고 있으며 아래 세가지 특징을 가짐
1. maximumPoolSize
1) Thread Pool에서 사용할 수 있는 최대 Thread의 개수
2) 하지만, 항상 최대로 유지하고 있지 않음(요청이 적을 경우 최대로 유지하는 것이 비효율적이므로)
3) Thread의 수 최적화를 위해 keepAliveTime 사용
2. keepAliveTime
1) keepAliveTime 시간 이후에도 요청이 없는 경우(=작업 큐 안에 작업이 없다) 쓰레드 소멸
2) 모든 Thread가 작업이 없어 소멸되는 문제 해결을 위해 corePoolSize 사용
3. corePoolSize
1) Thread Pool에서 사용할 수 있는 최소 Thread의 개수
2) 즉 Thread Pool이 가질 수 있는 Thread의 수는 최대 maximumPoolSize, 최소 corePoolSize만큼 가짐
여러개의 작업을 동시에 안정적으로 처리하고 싶을 때 Thread Pool은 효과적
-> Web Server에 적합
4. Web Server(Tomcat)
여러 요청을 동시에 받고 처리해야 하는 특징을 가지므로 Thread Pool 사용이 적합
Web Server의 예시로 Tomcat에 대해 작성해보자면
Tomcat?
1. SpringBoot의 내장 Servlet Container중 하나
2. Java 기반 WAS(Web Application Server)
3. Java의 ThreadPool 클래스와 유사한 자체 Thread Pool 구현체를 가짐
(org.apache.tomcat.util.threads.ThreadPoolExecutor)
Tomcat의 Thread Pool에서 추가적으로 알아야 할 특징
1. Max-Connections
1) Tomcat이 최대로 동시에 처리할 수 있는 Connection의 개수
2) Web 요청이 들어오면 Tomcat의 Connector가 Connection을 생성하면서 요청된 작업을 Thread Pool의 Thread에 연결
2. Accept-Count
1) Max-Connections 이상의 요청이 들어왔을 때 사용하는 대기열 Queue의 크기
2) Max-Connections + Accept-Count 이상의 요청이 들어왔을 때 추가적으로 들어오는 요청은 거절될 수 있음
5. Thread Pool을 활용해 원할한 Springboot 어플리케이션 운영 방법
Springboot의 Property를 활용해 Tomcat Thread Pool 설정 가능
1. server.tomcat.threads.max(default=200)
서버 어플리케이션이 동시에 처리할 수 있는 요청 개수와 관련
요청 수에 비해 너무 많이 설정했다면 놀고 있는 스레드가 많아지므로 비효율 발생
너무 적게 설정했다면 동시 처리 요청수(평균 응답 시간, TPS)가 감소
Thread 증가에 따라 CPU 오버헤드, 메모리 문제 발생 가능성 고려 필요
2. server.tomcat.threads.min-spare(default=10)
Thread Pool에서 최소한으로 유지할 Thread 개수
너무 많이 설정했다면 Thread Pool이 항상 유지해야 할 Thead 수가 많아지는 문제 발생
적게 설정했다면 요청에 따라 새로운 Thread가 계속 생성되는 비효율 발생
잘못 설정했을 때 사용하지 않는 Thread가 메모리를 차지하는 비효율 발생 고려 필요
3. server.tomcat.max-connections(default=8192)
동시에 처리할 수 있는 최대 Connection 개수
서버의 실질적인 동시 요청 처리 개수(Tomcat의 Connector Component 방식에 따라 변동)
Connector Component 방식
1) Blocking IO
1 Connection - 1 Thread
threads.max == max-connections
= Thread Pool의 최대 스레드 개수와 작거나 동일한 양의 Connection 유지 가능
2) Non-Blocking IO
N Connection - 1 Thread
threads.max <= max-connections
= Thread Pool의 최대 스레드 개수보다 많은 양의 Connection 유지 가능
최대 Thread 개수보다 작거나 같은 수의 max-connections을 설정하는 것은 비효율일 수 있음
4. server.tomcat.accept-count(default=100)
max-connections 이상의 요청이 들어왔을 때 사용하는 대기열 Queue 크기
부적절하거나 잘못된 요청이 한번에 많이 들어와 서버의 장애 발생을 방지
너무 크게 설정할 경우 대기열이 커져 메모리 문제 발생
너무 작게 설정할 경우 들어오는 요청을 거절해버릴 가능성 존재
6. Coroutine과 Thread
Coroutine은 Thread 내부에서 동작하는 경량화된 실행 단위
언어 런타임이나 라이브러리가 관리(Kotlin Coroutine)
Thread보다 가볍고 명시적인 suspend/resume 지점을 통해 실행 흐름 제어
별도의 완전한 스택 대신, 최소한의 상태 정보(Continuation)만 유지하여 메모리/컨텍스트 전환 비용을 줄임
OS Thread, User Thread 내에서 수많은 Coroutine을 동시에 실행할 수 있어 IO 바운드 작업 등에 효율적
코루틴 스케줄러는 언제 어느 코루틴이 실행될지를 결정
개발자가 명시적으로 양보(yield)하거나, 비동기 I/O 이벤트에 의해 자동으로 이루어짐
Youtube를 보고 Thread Pool에 대해 작성해봤다.
어플리케이션을 안정적으로 운영하기 위한 많은 방법들이 있겠지만 Thread Pool을 설정하는것이 방법중 하나라고 생각된다.
출처
반응형'개발 > Spring(boot)' 카테고리의 다른 글
Spring Batch와 Scheduler (0) 2025.03.30 CoroutineScope을 정의하는 방법 (0) 2025.03.10 SSE를 활용해 작업 진행률 전달하기 (2) 2025.02.16 Springboot에서 ChatGpt연동하기 (5) 2025.02.09 Custom Annotation을 만들고 AOP로 활용하는 법 (0) 2025.01.19