Servlet 역할
Http Request, Response 에 필요한 필수 기능을 제공하여 개발자가 비즈니스 로직에만 집중하게 해준다.
- TCP Socket connection 관리
- HTTP Request URL, Header, Body 파싱
- HTTP Response Header, Body 생성
Servlet 생명 주기
간단하게는 init -> service-> destroy 를 거친다.
1. init()
WAS (e.g. Tomcat) 이 띄워질 때 최초로 미리 등록해둔 서블릿을 모두 '싱글톤'으로 생성해둔다.
@WebServlet(name = "HelloServlet", urlPatterns = "Hello")
public class HelloServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
}
2. service()
비즈니스 로직을 처리한다. 개발자가 HTTP 요청/응답 객체를 핸들링 할 필요가 있을 때 req/res 객체를 사용할 수 있다.
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Business logic
super.service(req, resp);
}
3. destroy()
생성했던 HttpServletRequest, HttpServletResponse 를 모두 해지한다. (Garbage Collector 작동)
@Override
public void destroy() {
super.destroy();
}
4. 종료
WAS 시작 시점에 Servlet 객체가 생성되는 것처럼
WAS 종료 시점에 Servlet 객체는 해지된다.
Servlet 동작 순서
HelloServlet.java
// 1. Servlet Container 에서 Client 가 요청한 URL 에 따라 여기(Hello Servlet)로 분기
@WebServlet(name = "HelloServlet", urlPatterns = "Hello")
public class HelloServlet extends HttpServlet {
// 2. 메모리에 Servlet 객체 없으면 init 호출하여 Initialize (메모리에 적재)
// 💡 Servlet 객체 자체는 Singleton 으로 관리되기 때문에 한번만 호출된다.
// 단, HttpServletRequest , HttpServletResponse 만 요청 응답 당 1개씩 생겼다가 사라지는 것 뿐이다.
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
// 3. HttpServletRequest / HttpServletResponse 생성
// 4. 비즈니스 로직 실행
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Business logic
super.service(req, resp);
}
// 5. Get 인지 Post 인지 메소드 구분하여 메소드 호출 및 분기
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPut(req, resp);
}
//6. 로직 실행 후 HttpServletResponse 에 응답 write (동기/블로킹)
// 예전엔 여기서 Http 에서 읽을 html 을 만들어줬음.
// 7. 생성했던 HttpServletRequest, HttpServletResponse 해제
@Override
public void destroy() {
super.destroy();
}
}
대체 Servlet 을 누가 호출하나?
Thread Pool 에서 빌려온 thread .
Thread Pool 기법
WAS(Tomcat) 에서는 thread pool 기법을 사용한다.
Request connection 하나당 1개의 쓰레드가 무조건 동적으로 생성되고 해지된다고 가정하면 매우 비효율 적일 것이다.
쓰레드 생성과 해지는 비용이 많이 들기 때문에 미리 쓰레드 풀에 쓰레드를 생성해둔다.
(2023-03-19 기준 Spring 3.0.2 버전 Tomcat 8.x 는 200이 기본값이다.)
요청 처리에 필요한 쓰레드를 thread pool 에서 빌려 쓰고 반납한다.
구분 | 설명 | 기본값 |
server.tomcat.max-connections | WAS의 동시 요청 처리(연결 accept) 최대값 | 8192 |
server.tomcat.accept-count | max-connections 값 도달시 추가 요청을 대기시키는 TaskQueue 크기 |
100 |
server.tomcat.threads.max | WAS 가 활성화 할 수 있는 쓰레드 최대 개수 (Connector thread + Worker threads + Servlet threads 수 총합) |
200 |
server.tomcat.threads.min-spare | 항상 가용 가능한 쓰레드 최소 개수 | 100 |
만약 max-connection 수에 도달한 상태에서 새로운 요청이 오면 task queue 에 대기시킨다.
가용 가능한 worker thread 가 생기면 connector 는 task queue 로 부터 task 를 FIFO 로 꺼내 worker thread 에 할당한다.
max connection과 task queue 사이즈가 둘다 꽉찬 상태에서 추가 요청이 들어오면 Connection Refused 처리 된다.
NIO model Diagram
다음은 최신 버전의 SpringBoot 내의 Tomcat (10.1) 이 사용하고 있는 NIO 모델 다이어그램이다.
클라이언트 요청으로부터 하나의 HTTP Request/Response 가 쓰레드 상에서 어떻게 핸들링 되는지를 표현했다.
Worker Thread vs Servlet Thread
위 그림에서 Servlet Container 내부에 존재하는 thread 와 Servlet 에 존재하는 thread 는 무엇이 다른가?
Worker Thread | Servlet Thread | |
관리 주체 | Servlet Container | |
쓰레드 풀 | Worker thread pool | Servlet thread pool |
역할 | Low level processing - HTTP request method parsing - HTTP request body parsing - Request parsing 뒤 Servlet thread 로 서비스 처리 위임 - servlet thread 로부터 HTTP Response 를 받아 클라이언트로 응답 반환 |
Servlet 코드 실행 - Businsess logic - HTTP response 생성 및 쓰기 |
쓰레드 풀은 분리되어 있지만 둘다 Servlet Container 에 의해 관리된다.
NIO Connector 역할?
NIO Connector 는 org.apache.coyote.http11.Http11NioProtocol로 구현되어 있고 이는
SpringBoot 최신 버전에 기본 적용되는 구현체다. NIO Connector 의 역할은 다음과 같다.
- acceptor thread 라는 싱글 스레드를 사용하여 클라이언트 요청을 받아들인다. (accept)
- TaskQueue 생성
(task queue : Max-connections 에 도달하여 worker thread 가 모두 사용중일 때 대기되는 공간) - TaskQueue 관리
사용 가능한 Worker thread 가 생겼을 때 Task queue 에 대기중이던 task 를 FIFO 로 꺼내 worker thread 에 요청 처리를 위임.
🔗 Reference
'JVM > Spring' 카테고리의 다른 글
[Spring] DataJpa - Query methods, @Query (0) | 2024.12.14 |
---|---|
[Spring] 환경 분리 방법 (2) | 2023.10.29 |
[Spring] logback-spring.xml (0) | 2023.02.21 |
[Spring] ConfigurationProperties + ConfigurationPropertiesScan (0) | 2023.02.13 |
[SpringBoot] Naming methods in each layer (0) | 2023.02.09 |