📝 웹 서버, 웹 애플리케이션
📜 HTTP
- 웹은 모두 HTTP를 기반으로 통신한다.
- 예를 들어 웹 브라우저 클라이언트에서 URI를 통해 서버에 페이지를 요구할 경우 서버에서는 해당 페이지를 만들어 클라이언트에게 보여줄 것이다.
- 이때 클라이언트에서 서버로 데이터를 전송할 때, 서버에서 클라이언트로 데이터를 응답할 때 HTTP 프로토콜을 기반으로 동작하게 된다.
- 최근에는 거의 모든 것이 HTTP 프로토콜을 기반으로 이루어지고 있다.
- HTTP를 통해 우리가 일반적으로 알고 있는 HTML, TEXT, IMAGE, 음성, 영상 파일, JSON, XML(API) 등 거의 모든 형태의 데이터를 전송할 수 있다.
- 심지어는 서버 간에 데이터를 주고 받을 때도 대부분 HTTP를 사용한다.
- 지금은 바야흐로, HTTP의 시대라고 말할 수 있다.
📜 웹 서버(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는 위에서 말했듯이 정적 리소스, 애플리케이션 로직 모두 제공이 가능하기 때문이다.
- 다만 이렇게 하게되면 WAS가 너무 많은 역할을 담당하게 되며, 서버 과부하의 우려가 생긴다.
- 또한 가장 비싼 어플리케이션 로직이 정적 리소스에 의해 수행이 늦춰지거나 어려워지는 경우가 생길 수 있다.
- WAS에 장애가 발생하면 오류 화면 조차도 출력하지 못하기 때문에 위와 같은 구성으로도 충분히 커버할 수 있는 작은 시스템이 아닌 이상 WAS만 사용하는 것은 무리가 있다.
- 따라서 보통 위와 같이 정적 리소스는 웹 서버가 처리하고, 애플리케이션 로직과 같은 동적인 처리가 필요한 경우에만 WAS에 요청을 위임하여 동작하는 방식으로 구성하는 경우가 많다.
- 이로써 WAS는 비교적 중요한 애플리케이션 로직 처리에만 전담할 수 있게 된다.
- 위와 같이 구성하면, 정적 리소스가 많이 사용되는 경우 웹 서버만 따로 증설하면 되고, 애플리케이션 리소스가 많이 사용되면 WAS만 따로 증설하면 되므로 효율적인 리소스 관리가 가능해진다.
- 또한 정적 리소스만 제공하는 웹 서버는 죽는 경우가 드물기 때문에 WAS에 장애가 발생하더라도 클라이언트에게 오류 화면을 제공해줄 수 있다.
📝 서블릿
📜 서블릿
- HTML Form 데이터 전송을 통해 아래와 같이 요청을 보내게 되면 웹 브라우저에서는 해당 요청에 대한 HTTP 메시지를 생성하여 서버로 보내게 된다.
- 만약 우리가 웹 애플리케이션 서버를 밑바닥부터 모두 구현해야 한다면 위에서 말한 HTTP 메시지를 해석하여 올바른 응답을 보내줄 수 있도록 기능을 구현해야 하며, 그 과정은 아래와 같다.
- 그림을 보면 알겠지만 의미있는 비즈니스 로직은 전체 과정 중 극히 일부인 것을 확인할 수 있다.
- 즉, 이 경우에 우리는 꼭 필요한 작업이기는 하지만 상당히 귀찮은 작업을 매 요청마다 반복적으로 수행해주어야 한다.
- 이를 해결하기 위해 등장한 것이 서블릿이다.
- 서블릿은 위 그림에서 초록색 박스로 둘러싸인 의미있는 비즈니스 로직 부분을 제외한 모든 부분을 지원해준다.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) {
// 애플리케이션 로직
}
}
- 위 코드의 urlPatterns의 URL이 호출되면 서블릿 코드가 실행된다.
- 또한 HTTP 요청 정보를 편리하게 사용할 수 있도록 해주는 HttpServletRequest 객체와 HTTP 응답 정보를 편리하게 제공할 수 있도록 해주는 HttpServletResponse 객체를 제공하여 개발자가 HTTP 스펙을 매우 편리하게 사용할 수 있도록 해준다.
- 다만 개발자 스스로가 기본적인 HTTP 스펙을 어느정도는 숙지해야 HttpServletRequest 객체와 HttpServletResponse 객체를 사용하기 편리하다.
- 서블릿을 사용할 경우 HTTP 요청과 응답의 흐름의 위 그림과 같다.
- HTTP 요청시 WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체를 호출한다.
- 개발자는 해당 객체를 통해 HTTP 요청 정보를 사용하고 응답 정보를 편리하게 입력한다.
- 이후 WAS는 Response 객체에 담겨 있는 내용으로 HTTP 응답 정보를 생성하여 클라이언트로 전달하고 클라이언트에서는 이를 랜더링하여 화면에 출력한다.
📜 서블릿 컨테이너
- 서블릿 컨테이너란 Tomcat처럼 서블릿을 지원하는 WAS를 말하며, 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리한다.
- 서블릿 객체는 싱글톤으로 관리된다. 즉, 사용자의 요청이 올 때마다 계속 서블릿 객체를 생성하는 것은 비효율적이기 때문에 최초 로딩 시점에 서블릿 객체를 미리 만들어놓고 재활용하는 방식을 사용한다.
- 모든 사용자 요청은 동일한 서블릿 객체 인스턴스에 접근하게 되며, 때문에 공유 변수 사용에 주의해야 한다.
- 서블릿 객체는 서블릿 컨테이너가 종료되는 시점에 함께 종료된다.
- 사실 서블릿을 지원하는 WAS의 가장 큰 특징은 동시 요청을 위한 멀티 쓰레드 처리를 지원한다는 것이다.
📝 동시 요청 - 멀티 쓰레드
- 지금부터 다룰 개념은 트래픽이 많은 시스템을 컨트롤 할 때 꼭 필요한 개념이므로, 백엔드 개발자라면 해당 개념을 확실하게 잡아두고 넘어가도록 하자.
- 위에서 클라이언트가 URL을 통해 서버에 요청을 하게 되면 TCP/IP 커넥션이 연결되어 서블릿 객체를 호출한다고 하였는데, 그렇다면 이때 서블릿 객체를 도대체 누가 호출해주는 것인지를 먼저 알아보자.
📜 쓰레드
- 결론부터 말하자면 서블릿 객체를 호출하는 것은 쓰레드가 하는 역할이다.
- 쓰레드란 애플리케이션 코드를 하나하나 순차적으로 실행하는 것을 말하며, 자바 메인 메서드를 처음 수행할 때 실행되는 main이라는 이름의 요소 역시 쓰레드에 해당한다. 즉, 쓰레드가 없다면 자바 애플리케이션은 실행이 불가능하다.
- 이러한 쓰레드는 한 번에 하나의 코드 라인만 수행할 수 있으며, 따라서 동시 처리가 필요한 경우 쓰레드를 추가로 생성해야 한다.
- 장점?
- 즉, 다중 요청이 들어와서 쓰레드가 부족한 경우 요청마다 쓰레드를 생성하여 이를 해결할 수 있다.
- 이렇게 하면 리소스(CPU, 메모리)가 허용하는 한 동시 요청을 처리할 수 있고, 하나의 쓰레드가 지연되어도 나머지 쓰레드는 정상적으로 동작할 수 있다.
- 단점?
- 다만 쓰레드는 생성 비용이 매우 비싸고(쓰레드 생성에 사용되는 자원이 많아 응답 속도가 늦어질 수 있음), 추가로 쓰레드 컨텍스트 스위칭 비용이 발생하며, 쓰레드는 생성에 제한이 없기 때문에 어느 시점에는 CPU, 메모리 임계점을 넘어서 서버가 죽어버릴 수도 있다.
📜 쓰레드 풀
- 이를 해결하기 위해서 대부분의 WAS에서는 쓰레드 풀을 생성하여 미리 쓰레드를 만들어 저장해놓고 사용자 요청이 들어올 때마다 해당 풀에서 쓰레드를 꺼내쓰는 식으로 사용한다.
- 사용이 끝난 쓰레드는 종료하는 것이 아니라 다시 쓰레드 풀에 반납함으로써 쓰레드 생성과 종료에 따른 시간과 자원 사용을 최소화할 수 있다.
- 또한 생성 가능한 쓰레드의 최대치가 정해져 있으므로, 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다. (Tomcat의 경우 기본 최대 200개로 설정되어 있음)
- 만약 쓰레드 풀에 대기중인 쓰레드가 더이상 없다면 해당 요청은 원하는 수만큼 대기 상태로 전환하거나 거절할 수 있다.
📜 쓰레드 풀 - 실무 Tip
- WAS의 주요 튜닝 포인트는 최대 쓰레드(max thread)이다.
- 이 값을 너무 낮게 설정하면, 동시 요청이 많을 때 서버 리소스는 여유롭지만 클라이언트는 응답 지연이 많아질 것이다.
- 그렇다고 이 값을 너무 높게 설정하면, 동시 요청이 많을 때 CPU, 메모리 리소스 임계점 초과로 인해 서버가 다운될 수 있다.
- 때문에 최대 쓰레드를 시스템에 맞게 적절하게 설정하는 것이 중요하다.
- 그렇다면 적절한 최대 쓰레드 수는 어떻게 찾을 수 있을까?
- 이는 애플리케이션 로직의 복잡도와 CPU, 메모리, IO 리소스 상황에 따라 모두 다르기 때문에 최대한 실제 서비스와 유사한 수준의 충분한 성능 테스트를 수행해보면서 찾는 방법이 가장 안전하고 정확한 방법이다.
WAS의 멀티 쓰레드 지원 핵심은 멀티 쓰레드에 대한 부분은 모두 WAS가 처리하며, 개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 된다는 것이다. 즉, 개발자는 마치 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드를 개발하기만 하면 된다. 다만, 멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용하자.
📝 HTML, HTTP, API, CSR, SSR
📜 HTML, HTTP API
- 백엔드 개발자로써 서비스를 제공할 때 고민해야하는 방식은 대표적으로 3가지가 있다.
- 첫 번째는 정적 리소스이다. 정적 리소스라 함은 고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 말하며 주로 웹 브라우저를 의미한다.
- 두 번째는 HTML 페이지이다. 이는 동적으로 필요한 HTML 파일을 생성하여 전달해주는 것을 의미하며, 웹 브라우저에서는 해당 파일을 해석하여 화면에 출력하게 된다.
- 세 번째는 HTTP API 방식이다. 이는 HTML 페이지가 아닌 데이터를 전달하는 방식으로, 주로 JSON 형식을 사용하며 다양한 시스템에서 호출할 수 있다.
- 데이터만 주고받기 때문에 UI 화면이 따로 필요한 경우 이는 클라이언트 측에서 별도로 처리해야 한다.
- HTTP API 방식의 호출 종류로는 앱 클라이언트 to 서버, 웹 클라이언트 to 서버, 서버 to 서버가 있다.
📜 CSR, SSR
- 다만 최근에는 이 외에도 CSR, SSR이라는 서비스 제공 방식이 새롭게 등장하였다.
- CSR(Client Side Rendering)은 말 그대로 클라이언트 측에서 랜더링을 수행하는 방식으로, HTML 결과를 자바스크립트를 사용해 웹 브라우저에서 동적으로 생성하는 방식을 말한다.
- 주로 동적인 화면에 사용하는 방식이며, 웹 환경을 마치 앱 처럼 필요한 부분부분만 변경할 수 있다.
- 관련 기술로는 React, Vue.js 등이 존재한다.
- SSR(Server Side Rendering)은 반대로 서버 측에서 랜더링을 수행하는 방식으로, HTML 최종 결과를 서버에서 만들어서 웹 브라우저에 전달하는 방식을 말한다.
- 주로 정적인 화면에 사용하는 방식이며, 관련 기술로는 JSP, 타임리프 등이 있다.
CSR + SSR을 동시에 지원하는 웹 프레임워크도 있으며, SSR을 사용하더라도 자바스크립트를 사용해서 화면 일부를 동적으로 변경할 수 있다.
📌 References
'🍃 Spring, Spring Boot > 스프링 MVC' 카테고리의 다른 글
[Spring MVC] 6. 스프링 MVC - 기본 기능(2) (0) | 2023.06.22 |
---|---|
[Spring MVC] 5. 스프링 MVC - 기본 기능(1) (0) | 2023.06.22 |
[Spring MVC] 4. 스프링 MVC 구조 이해하기 (0) | 2023.06.19 |
[Spring MVC] 3. MVC 프레임워크 만들기 (0) | 2023.06.18 |
[Spring MVC] 2. MVC 패턴 (0) | 2023.06.16 |