스프링 MVC는 웹 애플리케이션 개발에서 널리 사용되는 프레임워크이다.
많은 사람들이 스프링을 왜 쓰냐 하면 거의 다 "스레드가 많아서", "대규모 트래픽 처리할 수 있어서"라고 한다.
사실 스레드 개수 문제가 아니다 🙅♀️
node.js는 적은 스레드로 논블로킹을 사용해서 충분히 트래픽을 처리한다.
스프링 MVC 기준 스레드 풀의 max값은 200이다.
server:
tomcat:
threads:
max: 200 # 생성할 수 있는 thread의 총 개수
min-spare: 10 # 항상 활성화 되어있는(idle) thread의 개수
max-connections: 8192 # 수립가능한 connection의 총 개수
accept-count: 100 # 작업큐의 사이즈
connection-timeout: 20000 # timeout 판단 기준 시간, 20초
port: 8080
왜 스프링MVC는 이렇게나 많은 스레드를 사용할까?
스프링 MVC는 블로킹 모델이다.
스프링 프레임워크는 Thread-per-Request 모델이면서 블로킹 모델을 기반으로 동작한다.
먼저 블로킹&논블로킹, 동기&비동기 개념을 모른다면 아래 포스팅을 읽어야 이해가 될 것이다.
Thread-per-Request이란?
Thread-per-Request이란 한 요청당 하나의 스레드가 할당되는 것을 말한다.
즉, 클라이언트가 서버에 요청을 보내면, 해당 요청을 처리하기 위해 스레드 풀(Thread Pool)에서 하나의 스레드가 할당된다.
블로킹 모델이란?
블로킹 모델은 요청을 처리하는 동안 특정 작업(네트워크 I/O, 데이터베이스 조회 등)이 완료될 때까지 스레드가 멈춰 기다리는 방식을 의미한다.
즉, 스레드가 특정 작업의 결과를 기다리며 대기하는 상태를 말한다.
블로킹 모델의 가장 큰 문제는 스레드가 작업 완료를 기다리며 멈춰 있는 동안 CPU가 놀게 되는 점이다.
CPU는 굉장히 비싼 하드웨어인 만큼 계산 및 작업 처리를 통해 높은 성능을 발휘할 수 있는데, 스레드가 블로킹 상태에 빠지면 해당 스레드를 위해 할당된 CPU 자원이 낭비되게 된다.
블로킹 모델 해결 방법
블로킹 상태로 인해 시스템 자원이 낭비되는 문제를 해결하기 위해 서버는 추가적인 스레드를 생성하여 블로킹 상태의 스레드를 대신할 수 있다. 이를 통해 CPU가 놀지 않도록 하고, 동시에 더 많은 요청을 처리할 수 있다.
추가 스레드 생성의 동작 방식
추가적인 스레드를 생성하여 블로킹 문제를 해결하는 방식은 다음과 같다.
단계 | 스레드 상태 | 작업 내용 |
---|---|---|
1 | 요청 수신 | 클라이언트 요청이 들어오면 스레드가 할당된다 |
2 | 작업 수행 | 네트워크 I/O 또는 데이터베이스 조회를 시작한다 |
3 | 블로킹 상태 진입 | 작업 완료를 기다리며 대기한다 |
4 | 추가 스레드 생성 | 다른 요청을 처리하기 위해 새로운 스레드가 생성된다 |
5 | 블로킹 해제 및 완료 | 작업 완료 후 스레드가 작업을 이어간다 |
블로킹 모델 + 다중 스레드의 치명적인 단점
블로킹 모델을 해결 하고자 다중 스레드를 사용하는 건 알겠다.
근데 스레드를 여러개 사용한다는건 스레드를 계속 전환해줘야된다는 것을 의미하기도 한다.
즉, 운영체제는 스레드 간 전환, 컨텍스트 스위칭(Context Switching)에 리소스를 소모하게 된다.
이는 또다른 CPU 자원의 낭비로 이어진다^^
컨텍스트 스위칭 비용을 아끼려면
CPU를 놀지 않게 하기 위해 스레드를 늘리는 건 알겠는데, 위에서 말한 컨텍스트 스위치 비용을 줄일 순 없을까?
1. 비동기 + 논블로킹 I/O 사용
가장 효과적인 방법은 블로킹 모델을 대체하는 것이다. 즉, 비동기 논블로킹 모델을 사용하는 것이다.
비동기 + 논블로킹 I/O 모델은 I/O 작업 중 스레드가 멈춰 기다리는 대신 작업 완료를 이벤트 기반으로 처리한다.
이를 통해 하나의 스레드가 여러 작업을 효율적으로 처리할 수 있다.
스프링 웹플럭스(Spring WebFlux)
대표적인 예로 스프링 웹플럭스가 있다.
작업이 완료되면 이벤트 루프(Event Loop)가 이를 감지하고 등록된 콜백을 실행한다.
스프링 웹플럭스는 블로킹 모델보다 "속도가 빠르다"기보다는 적은 리소스로 많은 트래픽을 처리할 수 있다는 점에서 유리하다. 블로킹 작업이 많다면 WebFlux를 도입하더라도 성능 향상이 제한적일 수 있다.
2. 스레드 풀 관리 최적화
비동기 논블로킹 모델로 전환이 어렵다면, 스레드 풀 관리 최적화를 통해 컨텍스트 스위칭 비용을 줄일 수 있다.
스레드 수를 적정 수준으로 제한하여 과도한 스레드 생성으로 인해 불필요한 컨텍스트 스위칭을 발생하지 않도록 설계한다.
'💻 Dev > Spring' 카테고리의 다른 글
[Spring Boot] gradle 프로젝트 불러오기 (0) | 2020.09.18 |
---|---|
[Spring] 1.스프링 프레임워크란?, IoC(스프링 컨테이너) (0) | 2020.09.02 |