본문 바로가기
개발 이론/Spring

요청에 대하여 쓰레드는 어떻게 획득하는가?

by dal_been 2024. 8. 30.
728x90

갑자기 프로젝트하다가 쓰레드, 쓰레드풀이 궁금해지면 쓰레드는 간단하게 worker라는건 알겠는데,..

그래서 요청에대해서 누가 쓰레드를 할당해줄까??가 궁금해졌다.

 


Tomcat이 시작할때

 

원초적으로 돌아가서 결국 쓰레드풀세팅과 쓰레드에 대한 세팅은 누가 해주는 걸까??로 시작해서 디버깅을 시작했다.

먼저 정리한 상황을 말하자면

1. Http11NioProtocol(AbstractProtocol) : 엔드포인트 새로운거 세팅

2. AbstractEndPoint(NioEndPoint, AbstractJessEndPoint) : 초기화 과정

3. Http11NoiProtocal : 위에서 초기화과정을 거친 EndPoint setter

4. 앞선 Endpoint : 쓰레드 할당

5. CoyoteAdapter : 세팅

6. Accepter : run()

 

AbstractProtocol

  •  Tomcat을 실행함에 있어 전체적인 진행을 해준다.

AbstractEndPoint

  • 애플리케이션과 관련된 환경설정을 해준다.
  • Thread와 관련된 설정도 여기서 기본적으로 이루어진다.
    public AbstractEndpoint() {
        this.bindState = AbstractEndpoint.BindState.UNBOUND;
        this.keepAliveTimeout = null;
        this.SSLEnabled = false;
        this.minSpareThreads = 10;
        this.maxThreads = 200;
        this.maxQueueSize = Integer.MAX_VALUE;
        this.threadsMaxIdleTime = 60000;
        this.threadPriority = 5;
        this.maxKeepAliveRequests = 100;
        this.name = "TP";
        this.daemon = true;
        this.useAsyncIO = true;
        this.negotiableProtocols = new ArrayList();
        this.handler = null;
        this.attributes = new HashMap();
    }

 

 

이후 해당 endpoint가 AbstractProtocol에 삽입되면

해당 endPoint에서 쓰레드를 할당해준다. 

 

// AbstractEndPoint 메서드중 하나
    public Executor getExecutor() {
        return this.executor;
    }

 

이후 CoyoteAdapter를 생성하고 Acceptor를 통해 run() 해준다.

  • CoyoteAdapter : 추후 HTTP 요청과 응답을 변환하고 중계하는 역할을 함
  • Acceptor : 네트워크 소켓을 수신하고, 클라이언트 연결을 처리하는 역할

 

결과적으로 궁금했던 쓰레드와 쓰레드풀에 대한 세팅은 AbstractEndpoint를 통해 설정된다.

 

 

그럼 요청에 대해서는 어떻게 쓰레드가 할당되는데?

 

만약 클라이언트가 api를 요청하게된다면

1. AbstractEndPoint : socket이 연결이 잘되었나 파악하고 + thread할당

2. AbstractProtocol : processor를 할당

3. Http11Processor : 클라이언트 Http요청을 파싱하여 Request객체를 생성

4. CoyoteAdapter : Processor로 받은 요청을 서블릿컨테이너에게 전달하고 요청을 처리하도록함

 

AbstractEndPoint

  • 간단하게 보면 소켓 연결을 확인하고 Executor를 통해 쓰레드를 할당해준다
    public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            } else {
                SocketProcessorBase<S> sc = null;
                if (this.processorCache != null) {
                    sc = (SocketProcessorBase)this.processorCache.pop();
                }

                if (sc == null) {
                    sc = this.createSocketProcessor(socketWrapper, event);
                } else {
                    sc.reset(socketWrapper, event);
                }

                Executor executor = this.getExecutor();
                if (dispatch && executor != null) {
                    executor.execute(sc);
                } else {
                    sc.run();
                }

                return true;
            }
       // 생략..
    }

 

AbstractProtocol

  • Processor를 할당하고 요청을 처리할 준비를 함
public AbstractEndpoint.Handler.SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
    // Socket 및 Processor 상태를 점검하고 요청 처리 시작
    Processor processor = getProcessor(wrapper);
    if (processor == null) {
        processor = createProcessor();
    }
    return processor.process(wrapper, status);  // Processor에 요청 처리 위임
}

 

Http11Processor

  • 클라이언트로부터 받은 요청을 파싱하고, Request, Resposne 객체 생성
public void service(SocketWrapperBase<S> socket) {
    // 요청을 파싱하여 Request와 Response 객체 생성
    Request request = new Request();
    Response response = new Response();
    adapter.service(request, response);  // CoyoteAdapter를 통해 서블릿 컨테이너에 요청 전달
}

 

CoyoteAdapter

  • Processor로부터 받은 Http 요청을 서블릿 컨테이너에게 전달및 요청을 처리하도록 함
public void service(Request request, Response response) {
    // 서블릿 요청 객체 생성 및 서블릿 컨테이너로 전달
    HttpServletRequest httpServletRequest = request.getRequest();
    HttpServletResponse httpServletResponse = response.getResponse();
    connector.getService().getContainer().getPipeline().getFirst().invoke(httpServletRequest, httpServletResponse);
}

 

 

조금 정리하자면

  • 네트워크 레벨 처리: AbstractEndpoint와 AbstractProtocol 단계는 네트워크 레벨에서 소켓을 관리하고, 요청을 적절한 스레드에 할당하여 처리할 준비를 하는 역할
  • 애플리케이션 레벨 처리: Http11Processor와 CoyoteAdapter 단계는 실제 HTTP 요청을 분석하고, 서블릿 컨테이너로 전달하여 애플리케이션 로직이 실행

 


쓰레드를 어떻게 할당되고 설정되는지 알아보았다.

다음에는 트랜젝션과 쓰레드의 관계, 커넥션풀과 커넥션을 알아볼 예정이다.

 

최대한 디버깅을 통해 공부해봤지만.. 내용이 정확하지 않을 수 있다. 부정확하게 있다면 언제든지 말씀해주세욥