스프링은 어떻게 동시에 수많은 요청을 처리할까요?

지난 포스팅에서는 Servlet Container 와 Java Thread Pool 에 대해 알아보았습니다.

 

이번 포스팅에서는 동시 요청을 처리하는 Tomcat 의 Thread Pool 에 대해 알아보겠습니다.

 


 

Tomcat 의 Thread Pool

지난 포스팅에서 알아본 것처럼, Spring 에서 클라이언트의 요청은 Tomcat 과 같은 Servlet Container 가 처리합니다.

Tomcat 의 Thread Pool 의 구조는 Java Thread Pool 과 유사하기 때문에 설정 방법과 효율적인 사용법에 대해 알아보도록 하겠습니다.

 

톰캣은 Spring Boot 의 내장 Servlet Container 중 하나로, application.yml 또는 application.properties 와 같은 애플리케이션 속성 파일로 Tomcat 의 Thread Pool 을 설정할 수 있습니다.

 

Properties

server:
  tomcat:
    threads:
      max: 200
      min-spare: 10
    max-connections: 8192
    accept-count: 100 # Task queue size
    connection-timeout: 20000

 

- server.tomcat.threads.max

Thread Pool 에서 사용할 최대 스레드 개수

 

Request 에 비해 스레드 개수를 너무 많게 설정하면, idle 스레드가 많아져 비효율이 발생하고

또 너무 적게 설정하면 동시에 처리할 수 있는 요청 수가 줄어들어 평균 응답 시간이 늘어나기 때문에 적절한 설정이 필요합니다.

 

- server.tomcat.threads.min-spare

Thread Pool 에서 최소한으로 유지할 Thread 개수

 

이 값을 많이 설정하게 된다면 Thread Pool 이 항상 유지해야 할 Thread 수가 많아지기 때문에 메모리를 많이 차지하게 됩니다.

 

- server.tomcat.accept-count

모든 요청 처리 스레드가 사용 중일 때 들어오는 커넥션 request 에 대한 최대 대기열 길이

즉, 작업 큐 사이즈를 의미합니다.

 

너무 크게 설정하면 대기열이 커지면서 메모리 문제를 유발할 수 있고, 너무 작게 설정하면 요청이 몰렸을 때 장애를 발생시킬 수 있습니다.

이 설정을 통해 부적절하거나 잘못된 요청이 한 번에 너무 많이 들어와서 서버에 장애를 발생시키는 것을 방지할 수 있습니다.

 

- server.tomcat.threads.max-connections

톰캣이 동시에 처리할 수 있는 최대 Connection 의 개수

 

 

톰캣은 accept-count 속성을 기반으로 연결을 수락할 수 있습니다.

 

예를 들어, max-connections(최대 연결 수) 가 3, max(최대 스레드 개수) 가 2, accept-count(대기열) 가 1 이라고 가정해보겠습니다. 이런 경우 최대 스레드 개수가 2개지만 작업 큐에 커넥션(Task)을 1개 넣을 수 있으므로, 연결을 수락할 수 있습니다.

 

Tomcat5 이후 지원하는 NIO 커넥터는 BIO 커넥터에 비해 스레드를 효율적으로 사용하지만, 두 방식 모두 대기열 큐가 가득차게 되면 연결 거절 오류를 리턴할 수 있습니다.

 

 

Thread Pool 을 설정하는 이유와 한계

앞에서 알아본 것과 같이 Thread Pool 의 세부 사항을 설정하는 이유는 무엇일까요?

이유는 여러가지가 있겠지만, 그 중 하나는 한정 된 서버 자원 내에서 클라이언트의 요청을 효율적으로 처리해주기 위해서입니다.

 

서버실이나 IDC 에 비싼 장비를 사두고 그 자원 내에서 최대한 많은 클라이언트의 요청을 받아야했을 때는 세부 설정이 중요했지만 현재 많은 기업은 AWS 를 통해 서비스하고 있습니다. 그렇기 때문에 서버의 리소스가 부족하다면 스레드를 줄이고 늘리며 요청을 처리하는 것보다 더 안정적인 AWS 의 인스턴스를 늘리는 방향으로도 문제를 해결할 수 있습니다.

 

또 Thread Pool 모델에는 더 근본적인 한계가 있습니다. Request 마다 하나의 Thread 를 할당해주는 Thread per request 라는 점입니다. 전세계 트래픽의 15% 를 차지한다고 알려진 넷플릭스와 같은 엄청난 서비스들이 등장하면서 하나의 요청에 하나의 스레드를 할당하는 전통적인 Spring MVC 모델은 한계를 가지게 되었습니다. 이러한 문제로 인해 요즘은 Reactive Progamming, Spring webflux 를 많이 사용한다고 하는데요. 다음 포스팅은 webflux 에 대해 알아보도록 하겠습니다.

 

 

 

Reference

복사했습니다!