Thread Pool

2023. 5. 25. 16:18Spring Framework/Apache Tomcat Server

아파치 톰캣(Apache Tomcat) 서버의 스레드 풀(Thread Pool)은 서버가 동시에 여러 클라이언트의 요청을 효율적으로 처리할 수 있도록 하는 중요한 메커니즘입니다. 웹 서버는 다수의 클라이언트로부터 들어오는 요청을 처리해야 하는데, 스레드 풀을 사용하면 요청이 올 때마다 새로운 스레드를 생성하는 대신 미리 생성된 스레드들을 재사용함으로써 시스템 자원을 절약하고 성능을 최적화할 수 있습니다.

스레드 풀의 개념

스레드 풀(Thread Pool)은 일정 수의 스레드를 미리 생성해두고 요청이 발생할 때 이 스레드를 할당하여 요청을 처리한 후, 다시 스레드 풀로 반환하는 방식으로 동작합니다. 이를 통해 새로운 스레드 생성과 소멸에 따른 오버헤드를 줄일 수 있으며, 동시에 처리 가능한 요청의 수를 제한하여 서버의 자원(메모리, CPU 등)을 효율적으로 관리할 수 있습니다.

톰캣에서는 각 커넥터(Connector)가 클라이언트와 서버 간의 통신을 처리하는데, 이때 스레드 풀이 사용됩니다. 커넥터는 요청을 수신한 후 이를 처리하기 위해 스레드 풀에서 스레드를 가져와 요청을 처리합니다. 스레드 풀이 없을 경우, 각 요청마다 스레드를 새로 생성하고 이를 사용한 후 파기하는 작업이 반복되므로 큰 성능 저하가 발생할 수 있습니다.

스레드 풀의 동작 방식

  1. 요청 수신 및 스레드 할당
    클라이언트로부터 요청이 들어오면, 톰캣의 커넥터가 이를 수신합니다. 이후 커넥터는 스레드 풀에서 사용 가능한 스레드를 할당받아 요청을 처리합니다.

  2. 스레드 처리
    할당된 스레드는 요청을 처리하며, 처리 완료 후 응답을 클라이언트로 반환합니다. 처리 중인 동안 해당 스레드는 다른 요청을 처리할 수 없습니다.

  3. 스레드 반환
    요청 처리가 완료되면 해당 스레드는 스레드 풀로 반환되어 새로운 요청을 처리할 준비 상태가 됩니다.

  4. 스레드 생성 및 소멸
    스레드 풀에서 스레드의 수는 톰캣 설정에 따라 동적으로 조절될 수 있습니다. 처음에는 최소 스레드 수만큼만 스레드를 유지하다가, 요청이 많아지면 설정된 최대 스레드 수만큼 스레드가 늘어납니다. 최대 수에 도달한 상태에서도 요청이 더 들어올 경우, 그 요청은 대기열에 추가되거나 처리할 수 없다는 응답을 받게 됩니다.

톰캣의 커넥터와 스레드 풀

톰캣에서는 각 커넥터(Connector)가 네트워크 요청을 처리합니다. 기본적으로 HTTP와 AJP 커넥터가 존재하며, 이 커넥터들이 클라이언트와의 통신을 처리하는데 이때 스레드 풀이 사용됩니다.

1. HTTP/1.1 커넥터

기본적으로 HTTP/1.1 프로토콜을 사용하여 클라이언트와 통신합니다. 설정 파일에서는 protocol="org.apache.coyote.http11.Http11NioProtocol"과 같은 형식으로 설정됩니다.

2. AJP 커넥터

AJP는 Apache JServ Protocol로, 톰캣과 웹 서버(예: Apache HTTP Server) 간의 빠른 통신을 위해 사용됩니다. 이 커넥터도 스레드 풀을 사용하여 요청을 처리합니다.

톰캣의 스레드 풀 관련 주요 설정

톰캣의 스레드 풀 설정은 server.xml 파일 내의 각 커넥터에서 정의할 수 있습니다. 여기서는 스레드 풀을 조정할 수 있는 주요 설정 항목들을 살펴보겠습니다.

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxThreads="200"
           minSpareThreads="10"
           acceptCount="100"
           executor="tomcatThreadPool" />

1. maxThreads

  • 설명: 커넥터가 사용할 수 있는 최대 스레드 수를 지정합니다.
  • 기본값: 200
  • 의미: 톰캣은 최대 200개의 요청을 동시에 처리할 수 있습니다. 요청이 maxThreads 수를 초과할 경우, 요청은 대기 상태가 되며, acceptCount 대기열을 초과하면 요청이 거부됩니다.

2. minSpareThreads

  • 설명: 스레드 풀이 항상 유지할 최소 유휴 스레드 수입니다.
  • 기본값: 10
  • 의미: 초기에는 이 최소 수만큼의 스레드가 생성되어 요청을 처리할 준비 상태에 있게 됩니다. 요청이 없더라도 이 수만큼의 스레드는 항상 준비 상태에 있습니다.

3. acceptCount

  • 설명: maxThreads에 도달한 후에도 요청을 처리하지 못할 때, 대기할 수 있는 최대 요청 수를 지정합니다.
  • 기본값: 100
  • 의미: 최대 스레드 수를 모두 사용 중일 때, 추가로 들어오는 100개의 요청은 대기열에 들어가며, 이를 초과하는 요청은 거부됩니다.

4. executor

  • 설명: 스레드 풀을 중앙에서 관리하는 Executor를 정의할 수 있습니다. Executor는 여러 커넥터가 스레드 풀을 공유할 수 있도록 해줍니다.
  • 예시: <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="300" minSpareThreads="50" />

톰캣 스레드 풀의 성능 튜닝

톰캣의 스레드 풀 설정을 적절하게 튜닝하면 서버 성능을 극대화할 수 있습니다. 아래는 성능을 고려한 스레드 풀 튜닝의 주요 포인트입니다.

1. maxThreads 최적화

  • 스레드 수를 너무 낮게 설정하면 서버가 많은 요청을 처리하지 못해 대기 시간이 증가할 수 있습니다. 반대로 너무 높게 설정하면 CPU가 스레드를 관리하는 데 필요한 자원이 급증하게 되어 성능이 저하될 수 있습니다. 따라서 애플리케이션의 성격(동기/비동기 처리, CPU/메모리 집약적 작업 등)을 고려하여 적절한 값을 설정해야 합니다.

2. minSpareThreads 조정

  • 이 값을 높게 설정하면 초기 요청 처리 속도가 빨라질 수 있습니다. 그러나 너무 많은 유휴 스레드를 유지하면 불필요한 메모리 낭비가 발생할 수 있습니다. 초기 부하를 감안해 적절한 수치를 설정하는 것이 좋습니다.

3. acceptCount 조정

  • maxThreads 수를 초과한 요청에 대해 대기열을 관리하는 역할을 합니다. 대기열 크기를 너무 작게 설정하면 부하가 높을 때 요청이 거부될 확률이 증가합니다. 적절한 서버 대기열 크기를 설정하여 요청이 거부되지 않도록 관리해야 합니다.

4. Executor 사용

  • 여러 커넥터가 있는 환경에서는 개별 커넥터마다 스레드 풀을 사용하는 것보다 Executor를 사용해 스레드 풀을 중앙에서 관리하는 것이 효율적일 수 있습니다. 이를 통해 메모리 사용량을 줄이고, 스레드 풀을 더 유연하게 관리할 수 있습니다.

비동기 처리와 스레드 풀

최근 웹 애플리케이션은 동시 처리 성능을 높이기 위해 비동기 요청 처리(Asynchronous Request Processing)를 사용하는 경우가 많습니다. 톰캣은 이러한 비동기 처리를 지원하며, 비동기 요청 처리에서는 스레드 풀이 더욱 중요한 역할을 합니다. 비동기 방식에서는 요청이 스레드를 오래 점유하지 않기 때문에 스레드 풀이 훨씬 적은 수의 스레드로 더 많은 요청을 처리할 수 있습니다.

비동기 처리를 활성화하기 위해 톰캣 설정뿐만 아니라 서블릿 코드에서 비동기 지원을 설정해야 합니다.

@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        AsyncContext asyncContext = request.startAsync();
        asyncContext.start(() -> {
            try {
                Thread.sleep(2000);  // 비동기 작업
                response.getWriter().write("Async Response");
                asyncContext.complete();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        });


 }
}

요약

톰캣 서버에서 스레드 풀(Thread Pool)은 서버가 동시에 여러 요청을 효율적으로 처리하기 위한 중요한 메커니즘입니다. 스레드 풀 설정을 통해 서버의 성능을 조정할 수 있으며, maxThreads, minSpareThreads, acceptCount와 같은 매개변수를 적절하게 조정함으로써 요청 처리 성능을 최적화할 수 있습니다. 톰캣의 스레드 풀은 성능 및 자원 관리에 핵심적인 역할을 하며, 서버 환경 및 애플리케이션 특성에 따라 유연하게 설정되어야 합니다.

'Spring Framework > Apache Tomcat Server' 카테고리의 다른 글

Host  (0) 2023.06.06
Context  (0) 2023.06.04
AJP (Apache JServ Protocol) Connector  (0) 2023.04.28
Realm  (0) 2023.04.25
Coyote Connector  (0) 2023.04.17