스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 : Web-app 이해

jkky98·2024년 8월 12일
0

Spring

목록 보기
29/77

Web Server and WAS

웹서버와 WAS는 보통 정적 리소스동적 리소스 제공의 차이로 구분된다.

  • 정적 리소스: 변화가 없는 HTML, CSS, JS, 이미지, 영상 등.
  • 동적 리소스: 프로그램 코드를 실행하여 비즈니스 로직을 처리하고, 처리 결과에 따라 동적으로 생성된 리소스.

경계의 모호성

사실, 웹서버WAS의 용어 및 경계는 매우 모호하다.

  • 웹서버도 프로그램 실행 기능을 포함할 수 있다.
  • WAS 역시 웹서버의 기능을 제공할 수 있다.

Java 환경에서의 구분

Java의 경우, Servlet Container를 제공하면 이를 WAS로 볼 수 있다.

  • 웹서버WAS는 둘 모두를 포괄할 수 있지만, WAS는 애플리케이션 코드를 실행하는 데 더 특화되었다고 이해할 수 있다.

그렇다면 WAS만 쓰면 되지 않을까?

WAS만 사용하게 된다면 WAS가 너무 많은 역할을 담당하게 된다.
WAS에서 정적 리소스 처리보다 더 중요한 작업은 보통 애플리케이션 로직 수행이다.

  • 만약 정적 리소스 처리 때문에 애플리케이션 로직 수행이 어려워진다면 큰 문제가 발생할 수 있다.

WAS 장애 시 문제점

WAS가 정적 리소스 처리와 동적 리소스 처리를 모두 담당할 경우,
WAS에 장애가 발생했을 때 오류 화면조차 노출되지 않을 수 있다.

웹서버와 WAS의 조합

보통은 웹 서버를 WAS 앞단에 두어 함께 사용한다.

  • 구성 예시

이렇게 구성하면:
1. 정적 리소스 요청이 많은 경우, 웹 서버를 증설.
2. 애플리케이션 로직 요청이 많은 경우, WAS를 증설.

단독으로 WAS나 웹서버가 모든 역할을 담당할 경우:

  • 정적 리소스 요청만 많은 상황에서도 서버를 증설해야 하므로 리소스 낭비가 발생한다.

안정성 측면

  • 정적 리소스만 제공하는 웹 서버는 잘 죽지 않는다.
  • 반면, 애플리케이션 로직을 처리하는 WAS는 여러 이유로 다운될 가능성이 크다.

위와 같은 시스템을 구성하면:

  • WAS에 에러가 발생했을 경우,
    웹 서버는 WAS와의 통신 실패를 감지하고 정적인 에러 페이지를 반환할 수 있다.

Servlet(서블릿)

왼쪽 상자의 경우 서버-클라이언트의 통신 흐름을 보여준다. HTTP로 통신하기 때문에 HTTP스펙에 맞게 요청 메시지를 구성하고 서버로 날려 비즈니스 로직을 처리하고 결과에 따른 응답메세지를 구성하여 클라이언트에게 응답한다.

실제로 HTTP 메시지를 작성하고, 이를 분석하여 내용을 판단하는 작업은 매우 지루하고 번거로운 일이다.
이 작업은 어느 정도 반복성도 존재한다.
이러한 불편함을 해소해주는 것이 바로 Servlet이다.

서블릿의 역할

  • HTTP 요청: 요청을 분석하고 필요한 데이터를 추출.
  • HTTP 응답: 응답 메시지를 생성.

Servlet의 기능
위 그림의 초록색 상자 부분만 프로그래머가 처리하고,

  • 요청Request 객체로,
  • 응답Response 객체로 서블릿이 생성하여 제공한다.

서블릿의 이점

HTTP 메시지를 다루는 번거로운 작업 대신, 프로그래머는:
1. 요청 분석 (Request 활용)
2. 응답 생성 (Response 활용)
을 통해 더욱 간편하게 작업할 수 있다.

프로그래머의 초점

백엔드 엔지니어에게 가장 중요한 작업은 비즈니스 로직 작성이다.

  • 위 그림에서 초록색 상자 부분이 비즈니스 로직 영역을 나타낸다.
  • 서블릿 도입으로 HTTP 요청과 응답 처리는 서블릿에 맡기고, 비즈니스 로직에 집중할 수 있게 된다.

현재의 대안: Spring Web Framework

사실, 더 우수한 방법이 존재한다.
Spring Web Framework를 사용하면:

  • RequestResponse를 다루는 작업조차 더욱 자동화되고 효율적으로 처리할 수 있다.
  • 개발자는 비즈니스 로직에만 집중할 수 있다.

스프링 부트를 설치하면 기본적으로 포함되는 Apache Tomcat을 기준으로 아래와 같은 프로세스가 작동한다.


요청-응답 프로세스

  1. 웹 브라우저 요청

    • HTTP 요청 메시지 송신.
  2. 톰캣에서 요청 처리

    • HTTP 요청 메시지를 기반으로 request, response 객체 생성.
  3. WAS 처리

    • WAS가 서블릿 컨테이너의 서블릿 객체에 생성된 request, response를 주입.
  4. 서블릿 객체 처리

    • request를 이용한 요청 처리.
    • response를 구성하여 응답 메시지 생성.
  5. WAS 응답 송신

    • WAS가 response 객체를 통해 응답 메시지를 생성하고, 웹 브라우저로 송신.

프로그래머의 역할

  • 굵게 표시된 부분

    • 프로그래머가 집중해서 신경 써야 할 작업:
      • 요청(request)의 내용 처리.
      • 응답(response) 메시지 구성.
  • 따라서 HTTP에 대한 지식은 중요하다.

    • 요청 메시지에 무엇이 담겨 있는지.
    • 어떻게 담겨 있는지.
    • 서블릿을 통해 어떻게 효율적으로 데이터를 사용할 수 있는지.

이런 이해가 있어야만 효율적인 도구를 훌륭하게 사용할 수 있다.


스프링의 간편함과 생략

  • 이후에는 스프링 웹 프레임워크를 통해 이러한 작업조차 더 간편하게 처리할 수 있다.
  • 간편함은 반복의 해소이며, 이는 생략의 연속이다.

생략 속의 이해

  • 서블릿은 완전한 자동화가 아니다.
    • 서블릿은 단지 HTTP 통신 작업을 간소화하는 도구이다.
    • 이는 반복적으로 호두를 쉽게 깔 수 있도록 만들어진 호두까기 기계와 같다.

프로그래머는 생략된 과정 속에서 이루어지는 보이지 않는 처리를 이해해야 한다.

Servlet Container

서블릿 컨테이너란, Tomcat과 같이 서블릿을 지원하는 WAS를 말한다.

  • 서블릿은 프로그래머가 비즈니스 로직에만 집중할 수 있도록 도와주는 역할을 한다.
  • Java 환경에서는, 서블릿 컨테이너 == WAS로 이해할 수 있다.

서블릿 객체 관리

  • 서블릿 객체는 싱글톤으로 관리된다.
    • 최초 로딩 시점에 서블릿 객체를 미리 생성하고, 이를 재활용한다.

주의점: 공유 변수 사용

  • 싱글톤 방식으로 관리되므로, 공유 변수 사용 시 주의가 필요하다.
    • 여러 요청이 하나의 서블릿 객체를 공유하므로, 데이터 충돌동시성 문제가 발생할 수 있다.
    • 공유 변수는 반드시 필요할 경우, 스레드 안전한 방식으로 처리해야 한다.

Multi-Thread

쓰레드는 애플리케이션 코드의 실행 단위를 담당하며, 동시 처리가 필요할 때 추가로 생성될 수 있다.


쓰레드와 요청 처리

  1. 단일 요청

    • WAS에 하나의 요청이 들어오면 휴식 중인 쓰레드를 호출하여 처리한다.
    • 이 쓰레드는 서블릿 객체를 호출하여 요청을 처리한다.
  2. 동시 요청

    • 만약 동시에 두 개의 요청이 들어왔을 때, 쓰레드가 하나뿐이라면:
      • 두 요청 중 하나는 쓰레드가 비워질 때까지 대기해야 한다.
    • 이를 해결하기 위해, WAS는 새로운 쓰레드를 생성하여 동시에 두 요청을 처리할 수 있다.

쓰레드의 비용

  • 쓰레드 생성 비용은 매우 높다.
    • 컨텍스트 스위칭 등으로 인해 CPU와 메모리를 소모.
  • 쓰레드 생성에는 제한이 없다.
    • 제한이 없는 점은 장점처럼 보이지만, 이는 단점이 될 수 있다.
    • 무제한으로 쓰레드를 생성하면 CPU와 메모리의 임계점을 초과하게 되어 서버가 다운될 수 있다.

결론

효율적인 쓰레드 관리가 중요하다:

  • 최소한의 쓰레드로 최대한의 성능을 낼 수 있도록 조율.
  • 쓰레드 수를 적절히 제한하는 메커니즘 도입 필요.
    • 예: 스레드 풀 사용.

Thread Pool

만약 위의 예시대로 200개의 쓰레드가 모두 사용중인 상황에서 추가 요청이 들어올 경우 요청들은 대기되거나(대기열) 거절된다.

톰캣의 경우 쓰레드 풀의 쓰레드 200개가 기본 설정이다. 디폴트이니 만큼 적당한 수를 잘 설정해준걸까? 아래 문단에서 이를 확인할 수 있다.

Thread Pool 실무에서

실무 최적화 과정에서 가장 효과를 크게 볼 수 있는 작업은
max thread(최대 쓰레드) 값을 적절히 설정하는 것이다.


최대 쓰레드 설정의 두 극단

  1. 최대 쓰레드가 너무 낮은 경우

    • 서버 리소스는 여유롭다.
    • 그러나 클라이언트는 응답 지연을 겪어 사용 경험(UX)이 저하된다.
    • 예: 음식점에 80% 이상의 자리가 남아 있지만, 사람들이 밖에서 줄을 서는 상황.
  2. 최대 쓰레드가 너무 높은 경우

    • 서버 자원이 한계에 달하면서 과부하 발생.
    • 들어온 요청들이 서버 자원을 과도하게 나눠 사용하며 성능 저하.
    • 예: 음식점이 꽉 찼는데도 손님을 계속 받는 경우, 두 사람이 한 의자를 공유하며 음식을 먹는 상황.
      요리사(컴퓨터 자원)가 과로로 쓰러질 수도 있다.
    • 결국 서버가 다운될 위험이 있다.
      (심지어 설정의 문제를 알아차리지 못할 수도 있다.)

적정 쓰레드 풀 설정

적절한 쓰레드 수는 상황에 따라 달라진다.

  • 톰캣 디폴트 값(200)이 적합한지 여부는 특정 상황에 따라 다르다.
  • 유일한 답:
    • 서버 컴퓨터의 성능,
    • 비즈니스 로직의 복잡도,
    • 요청의 특성 등을 고려하여 최적의 값을 찾아야 한다.

최적화 방법

  • 성능 테스트를 통해 적정 값을 찾아야 한다.

    • 배포 전 부하 테스트를 수행.
    • 대용량 요청 생성 도구:
      • Apache AB
      • nGrinder(Naver)
  • 테스트를 통해 서버의 자원 사용량, 응답 시간, 처리량 등을 분석하여 최적의 설정값을 도출한다.

백엔드가 일하는 두 가지 방식

SSR(Server Side Rendering)

서버 사이드 렌더링(Server-Side Rendering)은 HTML 최종 결과를 서버에서 생성하여 웹 브라우저에 전달하는 방식으로, Spring MVC에서는 뷰 템플릿(Thymeleaf, JSP 등)을, Django에서는 템플릿 시스템을 활용하는 MTV 패턴으로 구현된다. 보통 작은 프로젝트에서 많이 사용되며, 동적으로 HTML을 생성하여 전달하는 과정에서 프론트엔드 렌더링 작업까지 백엔드 엔지니어가 처리하는 방식이다.

CSR(Client Side Rendering)

CSR(Client-Side Rendering)은 서버가 HTML이 아닌 JSON 데이터를 전달하며, React나 Vue.js 같은 프론트엔드 라이브러리가 이를 받아 복잡하고 동적인 UI를 클라이언트에서 렌더링하는 방식이다. 과거에는 SSR(Server-Side Rendering)을 풀스택, CSR을 백엔드로 오해하기도 했지만, SSR도 백엔드 작업의 일환이며 CSR은 전문적으로 프론트엔드의 역할을 강조하는 방식이다. 백엔드 개발자는 JavaScript에 능숙할 필요는 없지만, 동적인 HTML 리소스를 간단히 제공할 수 있는 SSR 능력을 갖추는 것이 중요하다.

profile
자바집사의 거북이 수련법

0개의 댓글