Home 스프링 mvc는 왜 멀티 쓰레드 모델을 택했을까?
Post
Cancel

스프링 mvc는 왜 멀티 쓰레드 모델을 택했을까?

1. 글을 작성하게 된 계기


운영체제 공부를 할 때, 제이온님이 스프링은 왜 멀티 프로세서가 아닌 멀티 쓰레드를 사용할까요? 라는 질문을 했습니다. 이전에도 Youl님께 비슷한 질문을 받았는데요, 이 부분에 대해 명확하게 대답을 잘 못했습니다. 따라서 이번 기회에 이를 명확히 정리하기 위해 글을 작성하게 되었습니다.

스프링이 멀티 쓰레드를 채택한 이유는 다양하겠지만, 이번 포스팅에서는 운영체제(프로세스/쓰레드)의 관점에서 이를 살펴보겠습니다.





2. 왜 스프링 mvc는 멀티 프로세서가 아닌 멀티 쓰레드를 택했을까?


스프링 mvc가 멀티 쓰레드(Multi-Thread)를 택한 이유는 다양하겠지만 크게 자원(Resource)의 효율적 활용 , 컨텍스트 스위칭(Context Switching) 비용 감소 두 가지로 볼 수 있습니다. 이에 대해 살펴보겠습니다.

  1. 자원의 효율적 활용
  2. 각 쓰레드의 동작 방식





2-1. 자원의 효율적 활용

프로세스의 문맥(Context)을 쓰레드가 공유 할 수 있기 때문에 자원을 효율적으로 활용할 수 있습니다. 스프링은 애플리케이션이 구동될 때 객체의 중복 생성을 방지 하고, 메모리를 효율적으로 사용 하기 위해 빈(Bean)을 싱글 톤(Singleton)으로 등록합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
class AsyncThreadPoolConfiguration : AsyncConfigurer {

    @Bean(name = ["asyncThreadPool"])
    override fun getAsyncExecutor(): Executor {
        return ThreadPoolTaskExecutor().apply {
            corePoolSize = 50
            maxPoolSize = 200
            queueCapacity = 500
            initialize()
        }
    }
}







스프링에 등록된 빈은 애플리케이션 전역에서 사용될 수 있는데, 이를 운영체제의 입장에서 보면 프로세스의 문맥을 각 쓰레드가 공유 하는 것 이죠. 즉, 프로세스의 자원을 공유해 불필요한 메모리 사용을 줄이는 것입니다.

image







멀티 프로세서 환경에서는 각 프로세스가 독립적인 메모리 공간을 가지는데, 데이터 공유프로세스 동기화 와 같은 문제가 추가로 있기 때문에 오버헤드가 발생할 수 있습니다. 스프링은 멀티 쓰레드를 택함으로써 이런 비용을 절감한 것이죠.

image

참고로 동기화 문제는 멀티 쓰레드 환경에서도 발생할 수 있습니다.







2-2. 컨텍스트 스위칭 비용 감소

쓰레드 컨텍스트 스위칭 비용은 프로세스의 컨텍스트 스위칭 비용보다 저렴 하기 때문에 오버헤드가 적게 발생 합니다. 이를 이해하기 위해서는 스프링의 동작 원리를 이해해야 하는데, 이를 간단하게게 살펴보겠습니다.

Thread context switches are faster and have lower overhead, as they don’t require updating memory management structures. Process context switches are slower and involve updating memory management structures to switch between separate memory spaces and provide better isolation between processes.





애플리케이션에는 여러 명의 사용자가 동시에 요청을 보낼 수 있습니다. 스프링은 각 요청을 처리할 때, 하나의 쓰레드를 할당하는데, 사용자 요청이 올 때마다 쓰레드를 생성을 하면 비효율적이므로, 내부에 쓰레드 풀을 두고 한 번 생성한 쓰레드를 재사용합니다.

image







이때, 쓰레드 풀 내부의 쓰레드는 독립적으로 사용자 요청을 처리 하며, 각 쓰레드는 동기/Blocking으로 동작** 합니다. 정확히는 DispatcherServlet 부터요.

image

Tomcat은 Multiplexing을 통해 비동기로 사용자 요청을 수락하는데, 이는 이전에 작성한 포스팅을 참조해주세요.







각 쓰레드는 동기/Blocking으로 동작하는데, 사용자 요청 처리 중 Blocking이 발생하면 운영체제는 컨텍스트 스위칭을 합니다. 만약 멀티 프로세서 기반의 프로세서 컨텍스트 스위칭이라면 비용이 더 많이 발생하겠죠죠? 즉, 스프링은 멀티쓰레드 모델을 채택함으로써 컨텍스트트 스위칭 비용을 줄인 것입니다.

image







3. 정리


스프링 mvc는 멀티 프로세서가 아닌 멀티 쓰레드 모델을 채택했습니다. 여기에는 많은 이유가 있겠지만 자원의 효율적 사용, 컨텍스트 스위칭 비용 감소 크게 두 가지 이유가 있습니다. 이 외에도 다른 이유가 있을 수 있는데요, 이는 댓글로 좀 남겨주시면 감사하겠습니다. 😗

  1. 자원의 효율적 사용
  2. 컨텍스트 스위칭 비용 감소

This post is licensed under CC BY 4.0 by the author.

SpringBoot Docker-Compose 지원

빌드와 컴파일의 차이는 무엇일까?