스레드풀을 사용하는 이유
프로세스는 실행 중인 프로그램을 나타내며, 스레드는 프로세스의 작업 단위이다. 자바에서의 스레드는 주로 OS의 스레드에 일대일로 매핑된다. 이는 각 자바 스레드가 하나의 OS 스레드에 대응된다는 것을 의미한다. 그러나 이런 매핑 방식은 스레드 생성 비용과 Context Switching 빈도로 인해 효율적이지 않다. 이러한 문제에 대응하기 위해 사용되는 것이 스레드 풀이다. 스레드 풀은 미리 정의된 수의 스레드를 생성하고 관리하여 작업을 효율적으로 할당한다.
Http 요청은 어떻게 스레드에 할당되는가?
서버가 실행되면 NioConnector(비동기 네트워크 통신을 관리하는 주체)가 생성되고 그다음에는 NioProtocol(실제 통신 프로토콜 및 데이터 처리를 담당)이 생성되고 이후 NioEndPoint 객체가 생성되며, 이 객체는 Acceptor, Poller, 그리고 Selector를 내부에 포함하고 있다.
Acceptor는 주로 서버 소켓에서 연결을 기다리는 역할을 한다. 클라이언트가 연결을 시도하면 Acceptor는 해당 연결을 받아들여 Poller의 이벤트 큐에 추가한다. 이는 연결을 수락하고 해당 소켓을 통신에 참여시키는 역할을 한다.
Poller는 비동기적으로 여러 소켓을 관리한다. Poller의 Events는 Poller가 감시하고 있는 채널들의 이벤트 큐를 나타낸다. Poller는 준비된 채널을 스레드 풀에 전달하여 비동기적으로 작업을 처리한다. 여기서 준비된 채널은 소켓 연결이 수락되고 데이터까지 넘어온 채널을 의미한다. Selector는 Poller의 채널들을 관리하면서 이벤트가 발생한 채널이 있는지 확인한다.
정리하면 Acceptor가 소켓을 받아들이면 Poller의 큐에 해당 채널을 추가하고, Selector는 이를 감시하며 이벤트가 발생할 때까지 기다린다. Poller는 해당 채널을 스레드 풀에 전달한다.
WorkQueue는 스레드 풀에서 처리해야 할 작업들을 저장하는 큐이고, Workers는 스레드 풀에 속한 작업자 스레드들을 나타낸다. WorkQueue에는 처리할 수 있는 바로 그 시점에 쌓이기 때문에 워커들은 기다리는 시간 없이 바로 작업할 수 있다.
SpringBoot의 Tomcat 튜닝 포인트
server:
tomcat:
max-connections: 8192 // Acceptor가 수용하는 최대 연결 수
accept-count: 100 // 최대 연결 수용 후 저장되는 OS Queue Size
threads:
max: 200 // 늘릴 수 있는 최대 Worker 수
min-spare: 10 // 최소한으로 유지하는 Worker 수
max-connections
max-connections는 Acceptor가 수용할 수 있는 최대 연결 수를 지정한다. 이는 동시에 처리할 수 있는 클라이언트 연결의 최대 수를 나타낸다. Max-connections 이후의 요청은 톰캣에 연결되지 않고 accept-count 만큼 운영체제에서 관리된다.
accept-count
accept-count는 최대 연결 수용 후에 저장되는 운영체제 큐(OS Queue)의 크기를 나타낸다. Acceptor가 이미 최대 연결 수에 도달했을 때 새로운 연결을 대기열에 저장한다.
하지만, 특정 상황에서는 accept-count가 무시될 수 있다. 예를 들어, 설정한 accept-count가 운영 체제에서 허용하는 최대 대기 큐 크기를 초과할 경우, Tomcat은 운영 체제의 제한에 따라 대기 큐 크기를 조절할 수 있다. 이는 일부 운영 체제에서는 accept-count의 설정이 실제로는 제한되는 경우를 의미한다.
threads
max는 늘릴 수 있는 최대 워커 스레드 수를 나타내며 이는 동시에 처리할 수 있는 요청의 최대 수를 결정한다.
min-spare는 서버가 유휴 상태일 때 최소로 유지되는 워커 스레드의 수를 나타낸다. 이는 서버가 요청을 처리하기 위해 항상 일부 스레드를 활성화 상태로 유지한다.
톰캣은 최초에 min-spare 만큼의 워커들을 운영하다가 모든 워커들이 일하고 있다면 max 만큼까지 스레드를 생성한다. 추가 생성을 더 이상 할 수 없을 때부터 workQueue에 저장한다.
'JVM > SpringMVC' 카테고리의 다른 글
[SpringMVC] 스프링 이벤트 시스템 (0) | 2024.08.10 |
---|---|
빈 스코프: 빈의 생명 주기와 활용 (0) | 2024.03.09 |
CORS와 Preflight Request (0) | 2024.03.09 |
Spring WebSocket & STOMP (0) | 2023.12.15 |