Spring MVC는 웹 서버가 아니다?

Hansik Hwang·2023년 7월 25일
0
post-thumbnail

📌시작하며..

학부 시절에 다양한 프로젝트를 진행하며 사용했던 Spring Boot, Django 웹 어플리케이션 프레임워크을 통해서 처음으로 웹을 개발하고 Front-end/Back-end를 이해했다. 더불어 REST API 설계 규칙에 맞추어 client(Front-end)단 에서 원하는 요청을 수행하기 위한 API를 작성하고 매핑했다. 이때에 나는 동적인 처리(Client에서 넘어오는 데이터의 유효성을 검사하고, 원하는 요청에 따라 DB에서 데이터를 가져오고, 가져온 데이터를 원하는 요청에 따라 컨트롤 하는 등등..)를 하는 즉, 코드를 짜며 내부 로직을 작성하는 부분을 단순히 웹 서버라고 생각했다.

물론 Client, Server, DB 등과 같은 큰 범주에서는 웹 서버가 맞다. 하지만 나는 오늘 Web Server, Web Application Server의 측면에서 말하고자 한다.

내가 그렇게 MVC 구조에 맞게 코드를 짜며 작성했던 내부 로직들은 사실 Web Server가 아니라 Web Application Server의 Servlet 구현체라는 사실이다!


📌 원시 웹 구조

Client는 사용자가 웹에 접근하여 보고싶은 화면을 HTTP 메세지 형태로 Server로 Request한다. Web Server는 요청 받은 Request를 확인하여 사용자에게 적절한 HTML, CSS, JS, 이미지 파일 등을 보내준다. 이같이 초창기 웹의 구조에서 Web Server는 단순히 파일과 정보 등의 리소스를 저장하고 반환하는 정적인 처리 기능을 했다.

  • Web Server의 종류 : Apache, nginx 등등

하지만 Web의 발전과 함께 사용자는 점차 늘어나서 필요한 데이터는 많아지고 이를 관리하기 위한 데이터베이스가 생기고, 요청에 따라 사용자 별로 다른 화면을 보여주기 위한 동적인 처리 기능의 필요성이 대두 되었다.


📌 CGI

초기에 동적인 처리를 하기 위해서 Web Server 내부에서 CGI(Common Gateway Interface)라는 형태의 표준을 만들어 제공했다.

CGI는 서버와 응용 프로그램간에 데이터를 주고받기 위한 방법이나 규약을 뜻한다.

  1. 웹 브라우저의 HTML의 폼을 통해 요청이 웹 서버로 전달
  2. 웹 서버는 요청에 들어 있는 주소가 CGI 프로그램에 대응되는지 확인
  3. 대응될 경우 그 프로그램을 실행, 환경 변수와 표준 입력의 형태로 요청을 전달한다.
  4. 웹 서버는 CGI 프로그램이 표준 출력으로 돌려 보낸 내용을 그대로 응답으로 돌려 준다.

CGI는 하나의 응용 프로그램이 아니라 하나의 규약이기 때문에 다양한 언어로 구현한 CGI 프로그램이 존재 할 수 있다. (C, Java, PHP, ASP)

CGI 프로그램 장점

  • 규약만 준수하면 되기 때문에 언어, 플랫폼에 독립적이다.
  • Web Server에서 CGI 프로그램 실행이 안전하다.
  • 매우 가볍다.

CGI 프로그램 단점

  • 페이지 로드 사이에 데이터를 메모리에 캐싱 할 수 없다.
  • 모든 Request마다 DB connection을 새로 열어야 하기 때문에 느리다.
  • 모든 Request마다 새로운 프로세스를 생성해 요청하기 때문에 즉, 멀티 프로세싱 환경에서 Response를 주기 때문에 메모리를 과도하게 사용하고 시스템 부하가 커진다.

C를 이용한 CGI 코드 참고 : https://technet.tmaxsoft.com/upload/download/online/webtob/pver-20201021-000001/administrator-guide/appendix_cgi_sample.html


📌 WAS 구조의 등장

WAS(Web Application Server)?

DB 연동, 다양한 로직 처리 등 동적인 처리 기능을 담당하는 Server이다. 정적인 처리를 담당하는 Web Server와 DB 서버 사이에서 작동하는 미들웨어로써 DB연동 및 동적 페이지를 생성한다.

💡 짚고 넘어가야 할 부분

위의 사진에서 확인 할 수 있듯이 WAS 내부에 Web ServerWeb Container가 포함 되어 있다. 하지만 이것이 WAS를 정의하는 구조는 아니다. 웹 시스템은 다양한 형태로 정의 할 수 있다. 다음은 웹 시스템의 대표적인 구조 3가지이다.

  1. Client - Web Server - DB
  2. Clinet - WAS - DB
  3. Client - Web Server - WAS - DB

만약 1번 구조를 사용해 Web Server 내부에서 CGI를 통해 동적 처리를 한다면, 위에서 언급 했듯이 멀티 프로세스 환경에서 메모리 등 다양한 문제에 직면한다.

그렇다고 2번 구조 처럼 WAS만 사용한다면, WAS가 정적 처리까지 담당하면서 서버 부하가 커지게 된다.

따라서 우리는 Web Server와 WAS를 구분하여 3번 구조로 웹 시스템을 구성해야 한다.


📌 Client - Web Server - WAS - DB 구조

WAS는 기본적으로 동적 처리를 담당함으로 Web Server(이하 WS)와 WAS를 분리하여 효율적인 분산 처리를 가능하게 해야한다.

WS, WAS를 구분하여 분산처리 시 이점

  • 논리적으로 분리하여, 효율적인 리소스 관리

  • 물리적으로 분리하여, 보안 취약점에 따라 보안 강화
    - WAS에는 DB에 연동 되는 등 웹 어플리케이션 부분이 있기 때문에 외부와 바로 연결되면 중요한 내부 로직이 외부로 노출 될 수 있음

    • WS는 WAS에 비해 보안 취약 사항에 대해 제공 할 수 있는 기능이 많음
  • 하나의 WS에 여러대의 WAS를 연결 할 수 있다.
    - Load Balancing으로 WAS 동적 처리 기능의 부하를 줄임
    - Fail Over에 유용하여, 작동 중지된 WAS 대신 다른 WAS를 사용해 장애 극복
    - Fail Back에 유용하여, 작동 중지된 WAS를 재작동

  • 여러 Application 적용
    - 하나의 WS에 개별 기능에 적절한 언어로 구성된 WAS를 배치함으로써 성능을 향상


📌 WAS 내부 요소

이제 WS와 WAS의 명확한 차이점과 분리해야 하는 이유를 알았다면 WAS의 내부에 집중해 보자. 앞서 말 했듯이 WAS는 다양한 언어로 구현될 수 있지만, 국내에서는 Java가 압도적이기 때문에 통상적으로 국내 WAS라 함은 Java 기반의 WAS이고 그 중에서도 Tomcat이 일반적이다.

  • Java 기반 WAS의 종류 : Tomcat, JEUS, JBoss, WebSphere

1. Servlet?

우리가 개념적으로 이해하고 있는 WAS의 실질적 기능 즉, 동적 처리 기능을 담당하는 부분이 바로 Servlet이다.

  • Servlet은 자바로 만든 확장된 CGI의 형태이지, 자바로 구현된 CGI는 아니다!
  • 자바로 구현된 CGI != Servlet

    Servlet이 CGI와 다른 가장 큰 이유는 CGI는 멀티 프로세스 환경이지만, Servlet은 멀티 스레드 환경이다!

결국 Servlet도 Interface(표준)이기 때문에 구현체가 존재한다.
📌Spring MVC가 바로 웹 어플리케이션을 만드는데 특화된 Servlet의 구현체 인 것이다.📌
위의 문장이 바로 이번 게시물의 가장 핵심이고, 게시글 제목에 대한 답변인 것 이다.

2. Servlet Container?

Servlet Container란 구현되어 있는 servlet 클래스(구현체)를 규칙에 맞게 담고 관리해주는 Container이다.

  • 웹서버와의 통신 지원

서블릿 컨테이너는 서블릿과 웹서버가 손쉽게 통신할 수 있게 해준다. 일반적으로 소켓을 만들고 listen, accept 등을 해야하지만 서블릿 컨테이너는 이러한 기능을 API로 제공하여 복잡한 과정을 생략할 수 있게 해준다. 그래서 개발자가 서블릿에 구현해야 할 비지니스 로직에 대해서만 초점을 두게끔 도와준다.

  • 서블릿 생명주기 관리

서블릿 컨테이너는 서블릿 클래스를 로딩하여 인스턴스화하고, 초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출한다. 또한 수명이 다 된 서블릿을 적절하게 가비지 콜렉터를 호출하여 필요없는 자원 낭비를 막아준다.

  • 멀티쓰레드 지원 및 관리

서블릿 컨테이너는 Request가 올 때마다 새로운 자바 쓰레드를 하나 생성하는데, HTTP 서비스 메소드를 실행하고 나면, 쓰레드는 자동으로 죽게 된다. 원래는 쓰레드를 관리해야 하지만 서버가 다중 쓰레드를 생성 및 운영해주니 쓰레드의 안정성에 대해서 걱정하지 않아도 된다.


💡 짚고 넘어가야 할 부분

(1) 일반적인 WAS 구조에서 구현체를 관리하는 부분을 크게 Web Container라고 하며, Servlet Container는 자바 환경에서의 Web Container를 뜻함

(2) Servlet과 JSP는 같은 역할을 한다. 단순히 그 구조가 다른 것 이다.

  • Servlet : 자바 코드 내부에 HTML 작성
package test;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
   
	protected void doSomething(HttpServletRequest request, HttpServletResponse response){
		
		response.setContentType("text/html;charaset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("<h1>Welcome to HelloWorld!</h1>");
        out.println("<span>My name is Hansik!</span>");
        for(int i=0; i <10; i++){
        	out.println(i);
        }
		out.close();
	}

}

  • JSP : HTML 코드 내부에 Java 코드 작성
<html>
<head>
<meta charset="UTF-8">
<title>java util</title>
</head>
<body>
    <h1>Welcome to HelloWorld!</h1>
    <span>My name is Hansik!</span>
    <% 
        for(int i=0; i <10; i++){
        	out.println(i);
        };
    %> 
</body>
</html>

같은 역할을 하는데 왜 같이 사용할까?

Servlet만 사용하자니 HTML 코드 작성이 어렵고, JSP만 사용하자니 자바 코드 작성이 어렵기 때문에 Servlet을 MVC로 구현하여 복잡한 자바 로직을 작성하고, 결과 객체를 JSP로 던져 SSR으로 HTML 파일을 작성한다.


📌 전체 요청 처리 순서

  1. Web Server는 클라이언트로부터 HTTP 요청을 받는다.

  2. Web Server는 클라이언트의 요청을 WAS에 보낸다.

  3. WAS는 관련된 Servlet을 메모리에 올린다.

  4. WAS는 web.xml을 참조하여 해당 Servlet에 대한 Thread를 생성한다. (Thread Pool 이용)

  5. HttpServletRequest와 HttpServletResponse 객체를 생성하여 Servlet에 전달한다.

    • Thread는 Servlet의 service()를 호출한다.
    • service()는 요청에 맞게 doGet() 또는 doPost() 메서드를 호출한다.
  6. doGet(), doPost() 메서드는 인자에 맞게 생성된 적절한 동적 페이지를 Response 객체에 담아서 WAS에 전달한다.

  7. WAS는 Response 객체를 HttpResponse 형태로 바꾸어 Web Server에 전달한다.

  8. 생성된 Thread를 종료하고, HttpServletRequest와 HttpServletResponse객체를 제거한다.

📌 결론

이전의 WAS, Web Container, Servlet, Servlet Container를 잘 이해 했다면, 전체 요청 처리 순서에서 WASServlet Container로 변경해도 이상하지 않을 것이다.

따라서 WAS는 동적 처리를 담당하는 역할이고, 자바 기반의 WASServlet Container이며, 대표적인 Servlet Container가 바로 그 유명한 Tomcat이다!

참고 및 출처

profile
나의 보조기억장치💿

0개의 댓글