웹 애플리케이션의 이해

공부하는 감자·2024년 5월 19일
0

Spring Framework

목록 보기
5/5

현대 애플리케이션은 대부분 웹 환경에서 동작하는 웹 애플리케이션이다. 그리고 스프링 MVC라는 복잡한 웹 애플리케이션을 쉽고 빠르게 개발할 수 있도록 도와주는 Java 웹 프레임워크가 있다.

Java 백엔드 개발자는 이러한 웹 애플리케이션을 개발할 때 대부분 스프링 MVC를 사용한다.

백엔드 웹 기술을 학습하기 어려운 이유

Java 백엔드 웹 기술은 매우 방대하고 공부할 분량도 무척 많다. 웹 기술을 학습하기 어려운 이유는 대략 3가지 때문이다.

  1. HTTP
    • 모든 웹 기술은 HTTP를 기반으로 하고 있기 때문에, HTTP 기반 지식이 있어야 한다.
  2. 오래된 Java 백엔드 웹 개발
    • 오랜 시간 동안 불편한 점들을 개선하고 발전하면서 너무 많은 것들이 자동화 및 추상화되었다.
    • 따라서 과거의 어떤 문제 때문에 지금 이런 방식으로 개선되고 사용되는지, 과거의 문맥을 제대로 이해하고 사용하기가 어렵다.
    • ‘왜?’가 없이 단순히 사용법 위주로만 사용을 하게 된다.
  3. 많은 기능을 제공하는 스프링 MVC
    • 스프링 MVC는 실무 백엔드 개발에 필요한 모든 기능을 거의 다 제공한다.
    • 즉, 그만큼 방대하고 학습할 내용도 많다.

하지만 Spring MVC Framework의 기본 구조는 굉장히 탄탄하게 설계되어 있어서, 지금까지 수많은 기능이 추가되어도 그 기본 구조는 변하지 않았다.

따라서 스프링 MVC의 기본 구조를 확실하게 이해하는 것이 중요하다.


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

웹은 HTTP 프로토콜을 기반으로 통신을 한다. 다음과 같이 거의 모든 형태의 데이터 전송이 가능하다.

  • HTML, TEXT
  • 이미지, 음성, 영상, 파일
  • JSON, XML (API의 경우)

웹 서버란

  • 웹 서버란 HTTP를 기반으로 동작하는 서버이다.
  • 정적 리소스와 기타 부가 기능들을 제공한다.
    • 정적 리소스란, 특정 디렉토리에 있는 파일들을 그대로 전달해주는 것을 말한다.
    • 정적 HTML, CSS, JS, 이미지, 영상 등
  • 대표적으로 NGINX, APACHE 등이 있다.

웹 애플리케이션 서버

  • Web Application Server는 보통 WAS라고 부른다.
  • 웹 서버와 마찬가지로 HTTP를 기반으로 동작하며, 웹 서버의 기능들을 대부분 포함하고 있다.
  • 프로그램 코드를 실행해서 애플리케이션 로직을 수행할 수 있다.
    • 사용자에 따라서 사용자의 이름을 보여주거나 다른 화면을 보여줄 수 있다.
    • 즉, 동적인 HTML을 생성하거나 HTTP API(REST API)를 제공한다.
    • Servlet, JSP, Spring MVC 등이 WAS에서 동작한다.
  • 대표적으로 Tomcat, Jetty, Undertow 등이 있다.

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

  • 단순하게는 웹 서버는 정적 리소스를 제공하는 것, WAS는 애플리케이션 로직까지 실행할 수 있는 것으로 이해하면 된다.
  • 사실, 둘의 용어도 경계도 모호하다.
    • 웹 서버도 프로그램을 실행하는 기능을 포함하기도 한다.
    • 웹 애플리케이션 서버도 웹 서버의 기능을 제공한다.
  • 자바는 서블릿 컨테이너 기능을 제공하면 WAS라고 한다.
    • 하지만 서블릿 없이 자바 코드를 실행하는 서버 프레임워크도 있으므로 이 구분법도 애매하다.
  • WAS는 애플리케이션 코드를 실행하는데 더 특화되어 있다고 보는 것이 좋다.

웹 시스템 구성

WAS만 사용할 경우

  • WAS와 DB만을 사용하여 최소한의 시스템 구성이 가능하다.
  • WAS는 정적 리소스도 제공할 수 있고, 애플리케이션 로직도 제공이 가능하기 때문이다.

단점

  • WAS가 너무 많은 역할을 담당하고 있다.
    • 서버 과부하 우려
  • 가장 비싼 애플리케이션 로직이 정적 리소스 때문에 수행이 어려울 수 있다.
    • 정적 리소스를 제공하는 것은 있는 파일을 보내주면 되지만, 애플리케이션 로직은 비즈니스 로직이 들어가기 때문에 훨씬 비싸다.
  • WAS에 장애가 발생하면 웹 접속 자체가 안된다.
    • 접속 오류 화면조차도 노출이 불가능하다.

일반적인 구성

  • 웹 서버와 WAS, DB를 모두 둔다.
  • 웹 서버가 정적 리소스를 처리하고, 애플리케이션 로직과 같은 동적인 처리는 WAS에 요청을 위임한다.

장점

  • WAS는 중요한 애플리케이션 로직 처리를 전담할 수 있다.
  • 효율적으로 리소스를 관리할 수 있다.
    • 정적 리소스가 많이 사용되면 웹 서버를 증설한다.
    • 애플리케이션 리소스가 많이 사용되면 WAS를 증설한다.

참고

  • CDN이라는 정적 리소스를 캐시할 수 있는 중간 서버를 놓기도 한다.
  • API로 데이터만 제공하는 API 서버일 경우, 굳이 웹 서버를 두지 않아도 괜찮다.
    • WAS 서버만 구축

서블릿

회원가입을 하도록 HTTP 요청을 한다고 가정하자. 그렇다면 웹 애플리케이션 서버에서는 아래 항목을 직접 구현해야 한다.

  1. 서버 TCP/IP 연결 대기
  2. 소켓 연결
  3. HTTP 요청 메시지를 파싱해서 읽기
    • HTTP 메소드 방식과 URL 확인
    • Content-Type 확인
    • 데이터를 사용할 수 있도록 HTTP 메시지 바디의 내용을 파싱
  4. 저장 프로세스 실행
  5. 비즈니스 로직 실행
    • 데이터를 가지고 데이터베이스에 저장 요청
  6. HTTP 응답 메시지 생성 시작
    • HTTP 시작 라인 생성
    • Header 생성
    • 메시지 바디에 HTML 생성해서 입력
  7. TCP/IP에 응답 전달
  8. 소켓 종료

이 과정에서 실질적으로 비즈니스 로직은 5번 과정 뿐이다. 그런데 그러기 위해서 비즈니스 로직 실행 전후 단계가 너무 많다.

매번 이렇게 개발하고 있다면 비효율적이므로, 등장한 것이 Servlet이다.

Servlet

  • 비즈니스 로직(위의 5번 과정)을 제외한 모든 과정을 지원해준다.
    • 서블릿을 지원하는 WAS들이 이 기능들을 해준다.

특징

클라이언트에서 서버로 요청이 왔을 때, 서블릿 코드에 있는 service 메소드가 실행된다.

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest reqeust, HttpServletResponse response) {
		// 애플리케이션 로직
	}
}
  • urlPatterns 의 URL이 호출되면 서블릿 코드가 실행된다.
  • HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest 객체
  • HTTP 응답 정보를 편리하게 제공할 수 있는 HttpServletResponse 객체
  • 이처럼 개발자는 서블릿을 통해 HTTP 스펙을 매우 편리하게 사용할 수 있다.

동작 과정

  1. 웹 브라우저에서 localhost:8080/hello 로 요청을 한다.
  2. WAS 서버에서는 HTTP 요청 메시지를 기반으로 HttpServletRequest 객체와 HttpServletResponse 객체를 생성한다.
  3. 서블릿 컨테이너는 이렇게 생성한 두 객체를 helloServlet에 파라미터로 넘겨 실행한다.
  4. 실행이 끝나고 리턴되면, WAS는 HttpServletResponse 객체를 기반으로 HTTP 응답 메시지를 만든다.
  5. 웹 브라우저에 응답 메시지를 전달한다.

즉, HTTP 요청 시 다음과 같이 흘러간다.

  • WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체를 호출
  • 개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용
  • 개발자는 Response 객체에 HTTP 응답 정보를 편리하게 입력
  • WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성

서블릿 컨테이너

  • Tomcat처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다.
  • 서블릿 컨테이너는 다음과 같은 일을 한다.
    • 서블릿 객체를 생성, 초기화, 호출, 종료
    • 서블릿 객체의 생명주기 관리
  • 서블릿 객체는 싱글톤으로 관리한다.
    • 고객의 요청이 올 때마다 계속 객체를 생성하는 것은 비효율적이므로 최초 로딩 시점에 서블릿 객체를 미리 만들어 두고 재활용한다.
    • 따라서 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근한다.
    • 서블릿 컨테이너가 종료되면 함께 종료된다.
    • 공유 변수를 사용할 시 주의해야 한다.
  • JSP도 서블릿으로 변환되어서 사용한다.
  • 동시 요청을 위한 멀티 쓰레드 처리를 지원한다.

동시 요청 - 멀티 쓰레드

  1. TCP/IP 커넥션 연결
  2. WAS에서 서블릿 객체 호출 → Thread가 한다.

Thread

  • Thread는 애플리케이션 코드를 하나하나 순차적으로 실행한다.
  • Thread가 없다면 자바 애플리케이션 실행이 불가능하다.
    • 예를 들어, 자바 메인 메서드를 처음 실행하면 main이라는 이름의 Thread가 실행된다.

      public static void main(String[] args) {
      	// ...
      }
  • Thread는 한 번에 하나의 코드 라인만 수행한다.
  • 동시 처리가 필요하면 Thread를 추가로 생성해주어야 한다.

Thread가 하나일 경우

단일 요청 시

  1. HTTP 요청을 한다.
  2. WAS는 Thread를 할당한다.
  3. Thread는 코드를 실행한다.
  4. HTTP 응답을 하고 나면 Thread는 휴식을 한다.

다중 요청 시

  1. HTTP 요청이 1건 들어온다. (요청 1)
  2. WAS는 Thread를 할당한다.
  3. Thread는 요청 1을 처리하는데, 어떠한 이유로 처리가 지연되고 있다.
  4. HTTP 요청이 1건 더 들어온다. (요청 2)
  5. 요청 2는 Thread를 기다려야 한다.
    • 이렇게 기다리다가 Timeout 등이 발생하면서 요청 1과 2 모두 오류가 날 수 있다.

요청마다 Thread를 생성할 경우

다중 요청에서 다음과 같이 동작한다.

  1. HTTP 요청이 1건 들어온다. (요청 1)
  2. WAS는 Thread를 할당한다.
  3. Thread는 요청 1을 처리하는데, 어떠한 이유로 처리가 지연되고 있다.
  4. HTTP 요청이 1건 더 들어온다. (요청 2)
  5. 요청 2는 새로운 Thread를 할당한다.

장점

  • 동시 요청을 처리할 수 있다.
  • 리소스(CPU, 메모리)가 허용할 때까지 처리 가능
  • 하나의 Thread가 지연되어도 나머지 Thread는 정상 동작한다.

단점

  • Thread의 생성 비용은 매우 비싸다.
    • 고객의 요청이 올 때마다 Thread를 생성하면 응답 속도가 늦어진다.
  • Thread는 Context-swtiching 비용이 발생한다.
    • CPU의 코어는 Thread의 여러 개를 번갈아 실행하는데, 이를 컨텍스트 스위칭이라고 한다.
    • Thread가 많아지면 이 컨텍스트 스위칭 비용이 점점 커진다.
  • Thread 생성에 제한이 없다.
    • 고객 요청이 너무 많이 오면 CPU와 메모리 임계점을 넘어서 서버가 죽을 수 있다.

Thread Pool

요청마다 Thread를 생성할 때 발생하는 단점을 해결하기 위해 WAS는 내부에 Thread Pool을 사용한다.

  • 필요한 Thread를 Thread Pool에 보관하고 관리한다.
  • Thread Pool에 생성 가능한 Thread의 최대치를 관리한다.
    • Tomcat의 기본 설정은 최대 200개이다.
  • Thread Pool은 다음과 같이 사용한다.
    • Thread가 필요하면 Thread Pool에서 이미 생성되어 있는 Thread를 꺼내서 사용한다.
    • Thread의 사용을 종료하면 Thread Pool에 해당 Thread를 반납한다.
    • 최대 Thread가 모두 사용 중이어서 Thread Pool에 Thread가 없을 경우, 기다리는 요청은 거절하거나 특정 숫자만큼 대기하도록 설정할 수 있다.

동작 과정

  1. WAS의 Thread Pool에 미리 Thread를 만들어 둔다.
  2. HTTP 요청이 1건 들어온다. (요청 1)
  3. WAS는 Thread Pool에서 Thread를 꺼내 요청 1에게 할당한다.
  4. Thread는 요청 1을 처리하는데, 어떠한 이유로 처리가 지연되고 있다.
  5. HTTP 요청이 1건 더 들어온다. (요청 2)
  6. WAS는 Thread Pool에서 Thread를 꺼내 요청 2에게 할당한다.
  7. 요청이 끝나면 Thread를 Thread Pool에 반납한다.

장점

  • Thread가 미리 생성되어 있으므로 Thread를 생성하고 종료하는 비용(CPU)이 절약되고, 응답 시간이 빠르다.
  • 생성 가능한 Thread의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다.

성능 튜닝 관점에서

  • WAS의 주요 튜닝 포인트는 Max Thread(최대 쓰레드) 수이다.
  • 이 값이 너무 낮을 경우
    • 동시 요청이 많으면, 서버 리소스는 여유롭지만 클라이언트는 금방 응답 지연될 수 있다.
  • 이 값이 너무 높을 경우
    • 동시 요청이 많으면, CPU와 메모리 리소스 임계점 초과로 서버가 다운될 수 있다.
  • 따라서 적정값을 찾는 것이 중요하다.
    • 적정값은 애플리케이션 로직의 복잡도, CPU, 메모리, IO 리소스 상황에 따라 모두 다르다.
    • 따라서 최대한 실제 서비스와 유사하게 성능 테스트를 시도해야 한다.
    • 성능 테스트 툴로는 아파치 ab, 제이미터, nGrinder 등이 있다.

정리

  • 멀티 쓰레드에 대한 부분은 WAS가 처리해준다.
    • 개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 된다.
  • 멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈 등)는 주의해서 사용해야 한다.

HTML, HTTP API, CSR, SSR

정적 리소스

  • 주로 웹 브라우저들이 요청을 한다.
  • 웹 서버는 고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 제공한다.
    • 특정 폴더 아래에 이미 생성되어 있는 리소스 파일 제공

HTML 페이지

  • WAS는 동적으로 필요한 HTML 파일을 생성해서 전달한다.
    • 예를 들어서, 주문 내역 페이지를 보려고 한다면 주문 정보로 조회한 데이터로 HTML을 동적으로 생성하여 웹 브라우저에 제공한다.
  • 웹 브라우저는 HTML을 받아서 해석 후 사용자에게 보여준다.

HTTP API

  • HTML이 아니라 데이터를 전달한다.
    • 주로 JSON 형식을 사용한다.
    • 데이터만 주고 받으므로, UI 화면이 필요하면 클라이언트가 별도로 처리해야 한다.
  • 다양한 시스템에서 호출한다.

활용 상황

  • 앱 클라이언트 to 서버
    • 앱에 UI 컴포넌트가 있기 때문에 데이터만 전달 받는다.
    • 앱 클라이언트로는 아이폰, 안드로이드, PC 앱 등이 있다.
  • 웹 클라이언트 to 서버
    • 웹 브라우저에서 자바스크립트에서 ajax 등의 API를 통해 서버에 있는 API를 호출할 수 있다.
    • 이때 자바스크립트에서 필요한 데이터만 받아서 HTML을 동적으로 만들어서 뿌린다.
    • React, Vue.js와 같은 웹 클라이언트도 있다.
  • 서버 to 서버
    • 서버 간의 통신에는 데이터만 주고받으면 되므로 HTTP API를 사용한다.
    • 예를 들어, 주문 서버와 결제 서버가 서로 데이터를 주고 받아야 할 경우가 있다.
    • 기업 안에서 여러 서비스들이 잘게 쪼개져 있을 때(MSA) HTTP API를 통해서 많이 통신한다.

SSR과 CSR

서버 사이드 렌더링 (SSR)

  • 서버에서 (동적으로) HTML 최종 결과를 만들어서 웹 브라우저에 전달한다.
    • 웹 브라우저는 HTML을 보여주기만 하면 된다.
  • 주로 정적인 화면에 사용한다.
  • 관련 기술
    • JSP, Thymeleaf

클라이언트 사이드 렌더링 (CSR)

  • 웹 브라우저에서 자바스크립트를 사용해 HTML 결과를 동적으로 생성해서 적용한다.
    1. 웹 브라우저에서 서버로 HTML 요청을 한다.
    2. 서버에서는 빈 HTML과 자바스크립트 링크를 전달한다.
    3. 웹 브라우저에서 자바스크립트를 요청한다.
    4. 서버에서는 클라이언트 로직과 HTML 렌더링 코드가 들어있는 자바스크립트를 전달한다.
    5. 웹 브라우저에서 HTML API로 데이터를 요청한다.
    6. 서버가 JSON 형식으로 데이터를 전달한다.
    7. 웹 브라우저는 자바스크립트로 HTML 결과를 렌더링한다.
  • 주로 동적인 화면에 사용하며, 웹 환경을 마치 앱처럼 필요한 부분만 변경할 수 있다.
    • 대표적인 예로는 구글 지도, Gmail, 구글 캘린더 등이 있다.
  • 관련 기술
    • React, Vue.js

CSR과 SSR의 경계

  • React, Vue.js를 CSR+SSR 동시에 지원하는 웹 프레임워크도 있다.
  • SSR을 사용하더라도 자바스크립트를 사용하여 화면 일부를 동적으로 변경할 수 있다.

자바 백엔드 웹 기술 역사

과거의 기술

  • 1997년, TCP/IP 연결과 멀티 쓰레드 등의 고민을 해결하기 위해 Servlet 기술이 등장한다.
    • 그러나, Java 코드로 짜야 하기 때문에 HTML을 동적으로 생성하는 것이 굉장히 어렵다는 문제점이 있다.
  • 1999년, Servlet의 문제를 해결하기 위해서 JSP가 등장한다.
    • JSP는 최종적으로 서블릿으로 변한다.
    • HTML 생성은 편리하지만, 비즈니스 로직까지 포함하면서 너무 많은 역할을 담당한다는 문제가 생겼다.
  • 서블릿과 JSP를 조합하여 MVC 패턴을 사용
    • MVC 패턴은 모델, 뷰, 컨트롤러로 역할을 나누어 개발한다.
    • 핵심은 비즈니스 로직과 화면을 렌더링하는 부분을 분리하여, 관심사를 나누는 것이다.
  • 2000년대 초부터 MVC 프레임워크의 등장
    • MVC 패턴 자동화, 복잡한 웹 기술을 편리하게 사용할 수 있는 다양한 기능 지원
    • 스트럿츠, 웹워크, 스프링 MVC

현재의 기술

  • 애노테이션 기반의 스프링 MVC의 등장
    • @Controller
    • MVC 프레임워크는 스프링 프레임워크와 사용하려면 통합에 대한 고민이 필요했다.
    • 스프링 MVC는 스프링이 제공하기 때문에 통합에 대한 고민이 필요 없다.
  • 스프링 부트의 등장
    • 과거에는 서버에 WAS를 직접 설치하고 WAR 파일을 만들어서 설치한 WAS에 배포했다.
    • 스프링 부트는 빌드 결과(Jar)에 WAS 서버를 포함함으로써 빌드와 배포를 단순화했다.

최신 기술

  • 스프링 웹 기술이 다음 두 가지로 분화를 한다.
  • Web Servlet - Spring MVC
  • Web Reactive - Spring WebFlux

Spring WebFlux

  • 완전한 비동기 non-blocking 처리
  • 최소 Thread로 최대 성능
    • Thread의 개수를 CPU의 코어(혹은 +1)에 딱 맞춤으로써 Thread를 계속 돌아갈 수 있도록 한다.
    • Thread Context-switching 비용이 거의 들지 않으므로 효율화된다.
  • 함수형 스타일로 개발한다.
    • 동시처리 코드 효율화
  • 서블릿 기술을 사용하지 않는다.

다만, 다음과 같은 단점이 있다.

  • 웹 플럭스는 기술적 난이도가 매우 높다.
  • 아직 RDB 지원이 부족하다.
  • 일반 MVC의 Thread 모델도 충분히 빠르다.
  • 실무에서 아직 많이 사용하지 않는다.

자바 뷰 템플릿 역사

View Template이란

  • HTML을 편리하게 사용하는 뷰 기능을 말한다.
  • 주로 HTML을 백엔드에서 동적으로 생성하는 것을 말한다.

View Template의 종류

  • JSP
    • 속도가 느리다.
    • 기능이 부족하다.
  • 프리마커(Freemarker), 벨로시티(Velocity)
    • JSP의 속도 문제를 해결했다.
    • 다양한 기능을 제공한다.
    • HTML 파일을 열었을 때 JSP 코드가 다 보인다.
  • 타임리프(Thymeleaf)
    • 내추럴 템플릿: HTML의 모양을 유지하면서 뷰 템플릿 기능을 적용할 수 있다.
    • 스프링 MVC와 강력한 기능 통합
    • 최선의 선택, 단 성능은 프리마커, 벨로시티가 더 빠름

Reference

인프런 강의

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 | 김영한 - 인프런

profile
책을 읽거나 강의를 들으며 공부한 내용을 정리합니다. 가끔 개발하는데 있었던 이슈도 올립니다.

0개의 댓글