~/tech-blog/posts/spring-mvc-web-app — zsh

웹 애플리케이션 이해

웹 서버, 웹 애플리케이션 서버

웹 서버(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를 직접 구현하게 된다면 어떻게 해야 할까요?

  1. 웹 브라우저가 생성한 요청 HTTP 메시지를 모두 분석하고 분리해야 합니다.
  2. 서버는 TCP/IP 연결을 대기하고, 소켓을 연결합니다.
  3. 요청 메시지를 잘라서 파싱합니다.
  4. POST 방식인지, /save URL인지 확인한 뒤 파싱합니다.
  5. Content-type을 확인한 뒤 파싱합니다.
  6. 저장 프로세스를 실행합니다.
  7. 비즈니스 로직을 실행합니다.
    1. 데이터베이스에 저장을 요청합니다.
  8. HTTP 응답 메시지 생성을 시작합니다.
    1. HTTP 시작 라인을 생성합니다.
    2. Header를 생성합니다.
    3. 메시지 바디에 HTML을 생성해서 입력합니다.
  9. TCP/IP에 응답을 전달하고, 소켓을 종료합니다.

비즈니스 로직은 회원 이름과 나이를 받아 DB에 저장하면 끝나지만, 전 단계와 후 단계가 너무 많고 복잡해서 전 세계 개발자가 모두 똑같은 것을 개발하기에는 너무 비효율적입니다.

그래서 나온 것이 Servlet입니다. Servlet비즈니스 로직을 제외한 모든 것을 처리해 줍니다.

서블릿

  • urlPatterns(/hello)의 URL이 호출되면 서블릿 코드가 실행됩니다.
  • HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest를 제공합니다.
  • HTTP 응답 정보를 편리하게 제공할 수 있는 HttpServletResponse를 제공합니다.
  • 개발자는 HTTP 스펙을 매우 편리하게 사용할 수 있습니다.

동작 순서

  1. 웹 브라우저에서 서버에 요청합니다(localhost:8080/hello).
  2. 웹 애플리케이션 서버에서 request, response 객체를 생성합니다.
  3. 서블릿 컨테이너가 우리가 만든 helloServlet을 실행합니다.
  4. helloServlet이 종료되면 이전에 만든 response 객체를 바탕으로 응답 메시지를 만듭니다.
  5. 웹 브라우저에 응답 메시지를 전달합니다.

서블릿 컨테이너

  • 서블릿을 지원하는 WAS 안에는 서블릿 컨테이너가 존재합니다.
  • 서블릿 객체는 서블릿 컨테이너가 생성, 호출하며, 생명주기도 자동으로 관리해 줍니다.

서블릿

서블릿 컨테이너

  • 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 합니다.
  • 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리합니다.
  • 서블릿 객체는 싱글톤으로 관리됩니다.
    • 객체를 1개만 생성하고 공유해서 사용하는 방식으로, 모든 요청이 이를 공유해서 사용합니다.
    • 고객마다 요청이 다르기 때문에 request, response 객체는 계속 생성되는 것이 맞지만, helloServlet 자체는 굳이 계속 생성할 필요가 없습니다.
    • 최초 로딩 시점에 서블릿 객체를 미리 만들어 두고 재활용합니다.
    • 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근합니다.
    • 공유 변수를 사용할 때는 주의가 필요합니다. 멤버 변수를 사용할 때 특히 조심해야 합니다.
    • 서블릿 컨테이너가 종료되면 함께 종료됩니다.
  • JSP도 서블릿으로 변환되어 사용됩니다.
  • 동시 요청을 위한 멀티 쓰레드 처리를 지원합니다.
    • 개발자는 멀티 쓰레드에 크게 신경 쓰지 않아도 WAS가 자동으로 관리해 줍니다.

동시 요청 - 멀티 쓰레드

백엔드 개발자에게는 멀티 쓰레드가 중요합니다. 멀티 쓰레드 개념을 정리하지 못하면 트래픽이 많을 때 어떻게 처리해야 할지 알기 어렵습니다.

클라이언트 요청 ⇒ WAS 연결 ⇒ servlet 호출 ⇒ 응답 순으로 동작합니다.

그렇다면 서블릿 객체를 누가 호출할까요? 바로 쓰레드가 호출합니다.

쓰레드

  • 프로세스는 프로그램을 실행하고, 쓰레드는 프로그램 안에서 여러 갈래로 나뉩니다.
  • 애플리케이션 코드를 하나하나 순차적으로 실행하는 것이 쓰레드입니다.
  • 자바 메인 메서드를 처음 실행하면 main이라는 이름의 쓰레드가 실행됩니다.
  • 쓰레드가 없으면 자바 애플리케이션 실행이 불가능합니다.
  • 쓰레드는 한 번에 하나의 코드 라인만 수행합니다.
  • 동시 처리가 필요하면 쓰레드를 추가로 생성합니다.

다중 요청 - 쓰레드 하나 사용

사용자 요청이 WAS로 왔는데 여러 가지 이유로 처리가 지연되고 있는 상황에서 또 다른 사용자의 요청이 왔을 때, 하나의 쓰레드로 동시에 처리하려고 하면 두 요청이 모두 타임아웃되면서 오류가 발생합니다.

요청마다 쓰레드 생성

요청이 올 때마다 쓰레드를 생성하고, 사용이 끝나면 종료합니다.

장점

  • 동시 요청을 처리할 수 있습니다.
  • 리소스(CPU, 메모리)가 허용하는 한 계속 처리할 수 있습니다.
  • 하나의 쓰레드가 지연되어도 나머지 쓰레드는 정상 동작합니다.

단점

  • 쓰레드 생성 비용이 매우 비쌉니다.
    • 고객의 요청이 올 때마다 쓰레드를 생성하면 응답 속도가 늦어집니다.
  • 쓰레드는 컨텍스트 스위칭 비용이 발생합니다.
    • 쓰레드가 2개 이상일 때 발생하는 비용으로, CPU가 1개의 코어일 경우 쓰레드 2개를 동시에 사용할 수 없습니다. CPU 1개당 쓰레드를 순차적으로 1개씩 처리하는데, 이때 다른 쓰레드로 전환할 때 발생하는 비용이 컨텍스트 스위칭 비용입니다.
  • 쓰레드는 생성에 제한이 없습니다.
    • 고객 요청이 너무 많이 오면 CPU, 메모리 임계점을 넘어서 서버가 죽을 수 있습니다.

쓰레드 풀

단점을 해결하기 위해 보통 WAS는 다음과 같이 설계합니다.

  1. 요청1이 들어옵니다.
  2. 쓰레드 풀에 있는 쓰레드를 빌려줍니다.
  3. 요청2가 들어옵니다.
  4. 쓰레드 풀에 있는 쓰레드를 빌려줍니다.
  5. 쓰레드 풀에는 200개의 쓰레드가 존재합니다.
  6. 요청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편 — 백엔드 웹 개발 핵심 기술을 들으며 정리한 노트입니다.

이 시리즈 · 스프링 MVC
전체 4편
01웹 애플리케이션 이해 ← 지금 읽는 글

댓글

GitHub 계정으로 로그인하시면 댓글과 질문을 남기실 수 있습니다. 남겨 주신 글은 이 저장소의 Discussions에 쌓입니다.

● main 214 posts UTF-8 LF © 2026 코징 RSS · GitHub