개요
- SpringMVC 패턴을 이해하기 위해서 기본적으로 알아야 될 지식들을 정리하고자 한다.
웹 서버(Web Server)
- HTTP 기반으로 동작한다.
- 정적 리소스를 제공한다.
- 정적(파일)에는 HTML, CSS, JS, 이미지, 영상등이 있다.
- 웹 서버의 예로는 NGINX, APACHE 등이 있다.
웹 애플리케이션 서버(WAS - Web Application Server)
- HTTP 기반으로 동작한다.
- 프로그램 코드를 실행해서 애플리케이션 로직을 수행한다.
- 동적 HTML 를 처리한다.
- HTTP API(JSON) 등을 핸들링할 수 있다.
- 서블릿, JSP, 스프링 MVC 가 WAS에서 실행된다.
- 웹 서버가 하는 기능 대부분을 포함하고있다.
- 예로는 Tomcat, Undertow, Jetty 등이 있다.
WAS로만 애플리케이션을 구성하면 안될까?
- 가능은 하지만 매우 비효율적이다.
- WAS는 애플리케이션 코드를 실행하는데 특화되어 있다.
- 만약 WAS만으로 웹 시스템을 구성한다면, WAS가 너무 많은 역할을 담당하게 되고, 이는 서버 과부하로 이어질 수 있다.
- 또한 중요한 애플리케이션 로직이, 단순한 정적 리소스를 때문에 수행이 어려울 수 있다.
- WAS 장애시 오류 화면도 노출 불가능하다. (예를들어, "죄송합니다 현재 서버가 부하되어 사용이 어렵습니다"와 같은 화면)
- 한마디로 WAS를 단순하고 용량이 큰 정적리소스를 사용하기 위해 사용하기에는 아깝다!
웹 시스템 구성
- 정적 리소스는 웹 서버가 처리한다.
- 웹 서버는 애플리케이션 로직같은 동적인 처리가 필요하면 WAS에게 요청을 위임 한다.
- 이렇게 되면 웹 서버는 값싸고 단순한 정적리소스를 처리하고, WAS는 중요한 애플리케이션 로직만 전담해서 처리할 수 있다.
- 정적 리소스만 제공하는 웹서버는 잘 죽지 않는다. 그렇기 때문에 잘 죽는 WAS에서 오류 발생시 오류화면을 사용자에게 띄워줄 수 있다.
- 정적 리소스가 많아지면 웹서버를 증설하고, 애플리케이션 리소스가 많아지면 WAS를 증설하는 식으로 시스템은 발전할 수 있다.
서블릿
- 서블릿이란 - 클라이언트가 어떠한 요청을 하면 그에 대한 결과를 다시 전송해주어야 하는데, 이러한 역할을 하는 자바 프로그램입니다.
- 이러한 정의로는 서블릿의 기능을 이해하기 어렵다.
- 그럼 만약 서블릿이 없다면, 개발가는 어떠한 일들을 더해줘야 할까? 아래와 같은 일들을 개발자가 직접해줘야 한다.
```
- 서버 TCP/IP 대기, 소캣 연결
- HTTP 요청 메시지를 파싱해서 읽기
- POST 방식, /save URL 인지 확인
- Content-Type 확인
- HTTP 메시지 바디 내용 파싱
- 저장 프로세스 실행
- HTTP 응답 메시지 생성 시작 (HTTP 시작라인 생성, Header 생성, 메시지 바디에 HTML 생성해서 입력)
- TCP/IP에 응답 전달, 소켓 종료
```
- 보통 의미있는 비즈니스 로직은 6번과 7번 사이에 실행된다.
- 서블릿을 사용하게 된다면, 개발자는 비즈니스 로직에만 집중할 수 있다.
서버의 요청응답 구조
- HTTP 요청시
- WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체 호출
- 개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용
- 개발자는 Response 객체에 HTTP 응답 정보를 편리하게 입력
- WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성
서블릿 컨테이너
- 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다.
- 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리한다.
- 서블릿 객체는 싱글톤으로 관리한다.
- JSP도 서블릿으로 변환 되어서 사용된다.
- 동시 요청을 위한 멀티 쓰레드 처리를 지원한다.
쓰레드
- 백엔드 개발자는 멀티 쓰레드에 대한 개념은 필수이다.
- client가 요청을한 후 TCP/IP 연결이 된 다음 서블릿은 누가 호출하는가 -> 쓰레드가 호출한다.
- 애플리케니션 코드를 하나하나 순차적으로 실행하는 것은 쓰레드이다.
- 쓰레드가 없다면 자바 애플리케이션 실행이 불가능하다.
- 쓰레드는 한번에 하나의 코드 라인만 수행할 수 있다. (하나하나 순차적으로 내려간다. 건너뛰기는 안된다.)
- 동시 처리가 필요하면 쓰레드를 추가로 생성해야된다.
- 단일 쓰레드 환경에서 이미 쓰레드가 사용중이라면, 새로운 요청을 바로 처리할 수 없다.
- 이렇게 되면 두 연결 모두 정상적으로 작동하지 못하고 죽을 수 있다.
- 해결하고 싶다면 추가로 쓰레드를 생성하면 된다.
- 하지만 쓰레드를 새로 생성하는 비용과, 컨텍스트 스위칭 비용이 발생한다.
- 이러한 문제를 spring은 어떻게 보완해 주고 있는가
다중 쓰레드
- Spring은 쓰레드 풀에 일정 개수의 쓰레드를 생성해둔다.
- 요청을 처리할 때마다 쓰레드를 새로 생성하는 것이 아니라, 쓰레드 풀에서 쓰레드를 가져다가 사용한다.
- 쓰레드 풀에 생성 가능한 쓰레드의 최대치를 관리한다.
- 쓰레드의 사용아 종료되면 다시 쓰레드풀에 반납한다.
- 미리 생성된 쓰레드를 사용하기 때문에 쓰레드를 생성하고, 종료하는 비용이 절약되고, 응답시간이 빠르다.
- 생성 가능한 쓰레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다.
- 멀티 쓰레드에 대한 부분은 WAS가 처리하기 때문에 개발자는 멀티 쓰레드 관련 코드를 신경스지 않아도 된다.
- 개발자는 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스를 개발할 수 있다.
- 하지만 싱글톤 객체(서블릿, 스프링 빈)에서 공유변수를 잘관리해야 된다. (멀티쓰레드기 때문에 어디서 공유된 변수가 바뀔지 모름)
쓰레드 풀의 적정 숫자
- 너무 낮게 설정한다면 -> 동시요청이 많아지면, 서버 리소스는 여유롭지만, 클라이언트는 금방 응답이 지연된다.
- 너무 높게 설정하면 -> 동시요청이 많아지면, CPU, 메모리 리소스 임계점 초과로 서버가 다운된다.
- 애플리케이션 로직의 복잡도, CPU, 메모리, IO 리소스 상황에 따라 풀에 담길 쓰레드의 수는 달라진다.
- 성능 테스트 툴로는 아파티 ab, 제이미터, nGrinder등이 있다.
REFERENCES
- 김영한님의 스프링 MVC 1편
'Spring' 카테고리의 다른 글
빈 생명주기와 콜백 (0) | 2022.02.26 |
---|---|
Transactional Propagation (0) | 2022.02.26 |
BindingResult (0) | 2022.02.26 |
Bean Validation (BindingResult 개념을 먼저 숙지 해야된다.) (0) | 2022.02.26 |
ApplicationRunner,CommandLineRunner (0) | 2022.02.26 |