웹 서버, 웹 애플리케이션 서버
웹 서버(Web Server)
- HTTP 기반으로 동작합니다.
- 정적 리소스를 제공하고, 기타 부가 기능을 수행합니다.
- 정적(파일) HTML, CSS, JS, 이미지, 영상을 다룹니다.
- 예) NGINX, APACHE
웹 애플리케이션 서버(WAS - Web Application Server)
- HTTP 기반으로 동작합니다.
- 웹 서버 기능을 포함하며(정적 리소스 제공 기능 포함), 프로그램 코드를 실행해서 애플리케이션 로직을 수행합니다.
- 동적 HTML, HTTP API(JSON)
- 서블릿, JSP, 스프링 MVC
- 예) 톰캣(Tomcat), Jetty, Undertow
웹 서버, 웹 애플리케이션 서버(WAS) 차이
- 웹 서버는 정적 리소스를 제공하고, WAS는 애플리케이션 로직으로 동적인 정보를 제공합니다.
- 사실 둘의 용어와 경계는 모호합니다.
- 웹 서버도 프로그램을 실행하는 기능을 포함하기도 합니다.
- 웹 애플리케이션 서버도 웹 서버의 기능을 제공합니다.
- 자바에서는 서블릿 컨테이너 기능을 제공하면 WAS라고 부릅니다.
- 서블릿 없이 자바 코드를 실행하는 서버 프레임워크도 있습니다.
- WAS는 애플리케이션 코드를 실행하는 데 더 특화되어 있습니다.
웹 시스템 구성 - WAS, DB
- WAS, DB만으로도 시스템을 구성할 수 있습니다.
- WAS는 정적 리소스와 애플리케이션 로직을 모두 제공할 수 있습니다.
웹 시스템 구성 - WAS, DB
- WAS가 너무 많은 역할을 담당하게 되어 서버 과부하가 우려됩니다.
- 가장 비싼 애플리케이션 로직이 정적 리소스 처리 때문에 수행이 어려워질 수 있습니다.
- WAS에 장애가 발생하면 오류 화면조차 노출할 수 없습니다.
웹 시스템 구성 - WEB, WAS, DB
동작 순서
정적 데이터는 WEB 서버에서 처리하고, 동적 화면과 로직은 WAS가 처리한 뒤, DB에 접근하는 순서로 실행됩니다.
장점
- 정적 리소스는 웹 서버가 처리합니다.
- 웹 서버는 애플리케이션 로직 같은 동적인 처리가 필요하면 WAS에 요청을 위임합니다.
- WAS는 중요한 애플리케이션 로직 처리를 전담합니다.
웹 시스템 구성 - WEB, WAS, DB
- 효율적인 리소스 관리가 가능합니다.
- 정적 리소스 사용량이 많아지면 Web 서버를 증설합니다.
- 애플리케이션 리소스 사용량이 많아지면 WAS를 증설합니다.
웹 시스템 구성 - WEB, WAS, DB
- 정적 리소스만 제공하는 웹 서버는 잘 죽지 않습니다.
- 애플리케이션 로직이 동작하는 WAS 서버는 상대적으로 잘 죽습니다.
- WAS나 DB에 장애가 발생해도 WEB 서버가 오류 화면을 제공할 수 있습니다.
서블릿
HTML FORM 데이터 전송
POST 전송 - 저장
웹 브라우저에서 POST 방식으로 데이터를 전송하면, 클라이언트는 POST 방식의 /save 경로에 content-Type: application/x-www-form-urlencoded, username=kim&age=20 형식의 데이터를 보내게 됩니다.
서버에서 처리해야 하는 업무
웹 애플리케이션 서버 직접 구현
만약 우리가 WAS를 직접 구현하게 된다면 어떻게 해야 할까요?
- 웹 브라우저가 생성한 요청 HTTP 메시지를 모두 분석하고 분리해야 합니다.
- 서버는 TCP/IP 연결을 대기하고, 소켓을 연결합니다.
- 요청 메시지를 잘라서 파싱합니다.
- POST 방식인지,
/saveURL인지 확인한 뒤 파싱합니다. - Content-type을 확인한 뒤 파싱합니다.
- 저장 프로세스를 실행합니다.
- 비즈니스 로직을 실행합니다.
- 데이터베이스에 저장을 요청합니다.
- HTTP 응답 메시지 생성을 시작합니다.
- HTTP 시작 라인을 생성합니다.
- Header를 생성합니다.
- 메시지 바디에 HTML을 생성해서 입력합니다.
- TCP/IP에 응답을 전달하고, 소켓을 종료합니다.
비즈니스 로직은 회원 이름과 나이를 받아 DB에 저장하면 끝나지만, 전 단계와 후 단계가 너무 많고 복잡해서 전 세계 개발자가 모두 똑같은 것을 개발하기에는 너무 비효율적입니다.
그래서 나온 것이 Servlet입니다. Servlet은 비즈니스 로직을 제외한 모든 것을 처리해 줍니다.
서블릿
urlPatterns(/hello)의 URL이 호출되면 서블릿 코드가 실행됩니다.- HTTP 요청 정보를 편리하게 사용할 수 있는
HttpServletRequest를 제공합니다. - HTTP 응답 정보를 편리하게 제공할 수 있는
HttpServletResponse를 제공합니다. - 개발자는 HTTP 스펙을 매우 편리하게 사용할 수 있습니다.
동작 순서
- 웹 브라우저에서 서버에 요청합니다(
localhost:8080/hello). - 웹 애플리케이션 서버에서 request, response 객체를 생성합니다.
- 서블릿 컨테이너가 우리가 만든
helloServlet을 실행합니다. helloServlet이 종료되면 이전에 만든 response 객체를 바탕으로 응답 메시지를 만듭니다.- 웹 브라우저에 응답 메시지를 전달합니다.
서블릿 컨테이너
- 서블릿을 지원하는 WAS 안에는 서블릿 컨테이너가 존재합니다.
- 서블릿 객체는 서블릿 컨테이너가 생성, 호출하며, 생명주기도 자동으로 관리해 줍니다.
서블릿
서블릿 컨테이너
- 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 합니다.
- 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리합니다.
- 서블릿 객체는 싱글톤으로 관리됩니다.
- 객체를 1개만 생성하고 공유해서 사용하는 방식으로, 모든 요청이 이를 공유해서 사용합니다.
- 고객마다 요청이 다르기 때문에 request, response 객체는 계속 생성되는 것이 맞지만,
helloServlet자체는 굳이 계속 생성할 필요가 없습니다. - 최초 로딩 시점에 서블릿 객체를 미리 만들어 두고 재활용합니다.
- 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근합니다.
- 공유 변수를 사용할 때는 주의가 필요합니다. 멤버 변수를 사용할 때 특히 조심해야 합니다.
- 서블릿 컨테이너가 종료되면 함께 종료됩니다.
- JSP도 서블릿으로 변환되어 사용됩니다.
- 동시 요청을 위한 멀티 쓰레드 처리를 지원합니다.
- 개발자는 멀티 쓰레드에 크게 신경 쓰지 않아도 WAS가 자동으로 관리해 줍니다.
동시 요청 - 멀티 쓰레드
백엔드 개발자에게는 멀티 쓰레드가 중요합니다. 멀티 쓰레드 개념을 정리하지 못하면 트래픽이 많을 때 어떻게 처리해야 할지 알기 어렵습니다.
클라이언트 요청 ⇒ WAS 연결 ⇒ servlet 호출 ⇒ 응답 순으로 동작합니다.
그렇다면 서블릿 객체를 누가 호출할까요? 바로 쓰레드가 호출합니다.
쓰레드
- 프로세스는 프로그램을 실행하고, 쓰레드는 프로그램 안에서 여러 갈래로 나뉩니다.
- 애플리케이션 코드를 하나하나 순차적으로 실행하는 것이 쓰레드입니다.
- 자바 메인 메서드를 처음 실행하면 main이라는 이름의 쓰레드가 실행됩니다.
- 쓰레드가 없으면 자바 애플리케이션 실행이 불가능합니다.
- 쓰레드는 한 번에 하나의 코드 라인만 수행합니다.
- 동시 처리가 필요하면 쓰레드를 추가로 생성합니다.
다중 요청 - 쓰레드 하나 사용
사용자 요청이 WAS로 왔는데 여러 가지 이유로 처리가 지연되고 있는 상황에서 또 다른 사용자의 요청이 왔을 때, 하나의 쓰레드로 동시에 처리하려고 하면 두 요청이 모두 타임아웃되면서 오류가 발생합니다.
요청마다 쓰레드 생성
요청이 올 때마다 쓰레드를 생성하고, 사용이 끝나면 종료합니다.
장점
- 동시 요청을 처리할 수 있습니다.
- 리소스(CPU, 메모리)가 허용하는 한 계속 처리할 수 있습니다.
- 하나의 쓰레드가 지연되어도 나머지 쓰레드는 정상 동작합니다.
단점
- 쓰레드 생성 비용이 매우 비쌉니다.
- 고객의 요청이 올 때마다 쓰레드를 생성하면 응답 속도가 늦어집니다.
- 쓰레드는 컨텍스트 스위칭 비용이 발생합니다.
- 쓰레드가 2개 이상일 때 발생하는 비용으로, CPU가 1개의 코어일 경우 쓰레드 2개를 동시에 사용할 수 없습니다. CPU 1개당 쓰레드를 순차적으로 1개씩 처리하는데, 이때 다른 쓰레드로 전환할 때 발생하는 비용이 컨텍스트 스위칭 비용입니다.
- 쓰레드는 생성에 제한이 없습니다.
- 고객 요청이 너무 많이 오면 CPU, 메모리 임계점을 넘어서 서버가 죽을 수 있습니다.
쓰레드 풀
단점을 해결하기 위해 보통 WAS는 다음과 같이 설계합니다.
요청1이 들어옵니다.- 쓰레드 풀에 있는 쓰레드를 빌려줍니다.
요청2가 들어옵니다.- 쓰레드 풀에 있는 쓰레드를 빌려줍니다.
- 쓰레드 풀에는 200개의 쓰레드가 존재합니다.
요청1,요청2의 처리가 끝나고 응답이 보내지면 쓰레드는 쓰레드 풀로 다시 반납됩니다.
200개 이상의 고객 요청이 오면, 클라이언트는 대기하거나 거절될 수 있습니다.
쓰레드 풀
요청마다 쓰레드를 생성하는 방식의 단점 보완
- 특징
- 필요한 쓰레드를 쓰레드 풀에 보관하고 관리합니다.
- 쓰레드 풀에 생성 가능한 쓰레드의 최대치를 관리합니다. 톰캣은 최대 200개를 기본 설정으로 제공합니다(변경 가능).
- 사용
- 쓰레드가 필요하면 이미 생성되어 있는 쓰레드를 쓰레드 풀에서 꺼내서 사용합니다.
- 사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납합니다.
- 최대 쓰레드가 모두 사용 중이어서 쓰레드 풀에 쓰레드가 없으면, 기다리는 요청을 거절하거나 특정 숫자만큼 대기하도록 설정할 수 있습니다.
- 장점
- 쓰레드가 미리 생성되어 있으므로 생성·종료 비용(CPU)이 절약되고, 응답 시간이 빠릅니다.
- 생성 가능한 쓰레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있습니다.
WAS의 멀티 쓰레드 지원
핵심
- 멀티 쓰레드에 대한 부분은 WAS가 처리합니다.
- 개발자가 멀티 쓰레드 관련 코드를 신경 쓰지 않아도 됩니다.
- 개발자는 마치 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드를 개발할 수 있습니다.
- 멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용해야 합니다.
HTML, HTTP API, CSR, SSR
정적 리소스
- 고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 제공합니다.
- 주로 웹 브라우저에서 사용됩니다.
HTML 페이지
- 동적으로 필요한 HTML 파일을 생성해서 전달합니다.
- 웹 브라우저가 HTML을 해석합니다.
HTTP API
- HTML이 아니라 데이터를 전달합니다.
- 주로 JSON 형식을 사용합니다.
- 다양한 시스템에서 호출됩니다.
HTTP API
- 다양한 시스템에서 호출됩니다.
- 데이터만 주고받으며, UI 화면이 필요하면 클라이언트가 별도로 처리합니다.
- 앱, 웹 클라이언트, 서버 간 통신에서 사용됩니다.
서버사이드 렌더링, 클라이언트 사이드 렌더링
- SSR - 서버 사이드 렌더링
- HTML 최종 결과를 서버에서 만들어서 웹 브라우저에 전달합니다.
- 주로 정적인 화면에 사용됩니다.
- 관련 기술: JSP, 타임리프 → 백엔드 개발자
- CSR - 클라이언트 사이드 렌더링
- HTML 결과를 자바스크립트를 사용해 웹 브라우저에서 동적으로 생성해서 적용합니다.
- 주로 동적인 화면에 사용되며, 웹 환경을 마치 앱처럼 필요한 부분만 변경할 수 있습니다.
- 관련 기술: React, Vue.js → 웹 프론트엔드 개발자
- 참고
- React, Vue.js는 CSR과 SSR을 동시에 지원하는 웹 프레임워크로도 사용됩니다.
- SSR을 사용하더라도 자바스크립트를 사용해서 화면 일부를 동적으로 변경할 수 있습니다.
이 글은 인프런 김영한 님의 스프링 MVC 1편 — 백엔드 웹 개발 핵심 기술을 들으며 정리한 노트입니다.
댓글
GitHub 계정으로 로그인하시면 댓글과 질문을 남기실 수 있습니다. 남겨 주신 글은 이 저장소의 Discussions에 쌓입니다.