•
회의 날짜: 2022/12/30 (금)
•
회의 장소: discord 라운지
•
참석자: 김솔배, 구연지, 안지영, 김재근
[회고 사진]
[이번 스터디 공부한 내용
김솔배
우리가 사용하는 Web은 HTTP로 데이터로 전송이 이루어져 있다.
WEB : 정적 리소스
WAS : 동적 로직 (애플리케이션 로직)
웹 어플리케이션의 발전
서블릿 → JSP → MVC
서블릿
개발자가 해야할 HTTP 요청 메세지를 읽거나, 응답메세지를 작성하여 반환한다.
서블릿 = WAS
즉, Http 요청메세지를 읽고, 반환메세지를 작성하여 리턴
•
WAS는 Request, Response객체를 새로 만들어서 서블릿 객체를 호출한다.
•
서블릿 객체는 싱글톤으로 관리
•
JSP도 서블릿으로 변환 되어서 사용
동시 요청을 위한 멀티 쓰레드 처리 지원
멀티 쓰레드 - 동시요철
클라이언트에서 요청 시 응답하는 과정
•
요청이 오면 서블릿 객체를 호출 하는 것은? → 쓰레드
◦
애플리케이션 코드를 하나하나 순차적으로 실행하는 것은 쓰레드
•
쓰레드는 한번에 하나의 코드 라인만 수행 → 동시 처리가 필요하면 쓰레드를 추가로 생성
쓰레드 풀 - 요청마다 쓰레드 생성의 단점을 보완
•
특징
◦
필요한 쓰레드를 쓰레드 풀에 보관하고 관리한다.
◦
쓰레드 풀에 생성 가능한 쓰레드의 최대치를 관리한다. 톰캣은 최대 200개 기본 설정 (변경 가능)
•
사용
◦
쓰레드가 필요하면, 이미 생성되어 있는 쓰레드를 쓰레드 풀에서 꺼내서 사용한다.
◦
사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납한다.
◦
최대 쓰레드가 모두 사용중이어서 쓰레드 풀에 쓰레드가 없으면?
▪
기다리는 요청은 거절하거나 특정 숫자만큼만 대기하도록 설정할 수 있다.
•
장점
◦
쓰레드가 미리 생성되어 있으므로, 쓰레드를 생성하고 종료하는 비용(CPU)이 절약되고, 응답 시간이 빠르다.
◦
생성 가능한 쓰레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다. → 서버를 늘리긴 해야한다.
WAS는 멀티 쓰레드를 지원한다 - 가장 중요한 점
◦
멀티 쓰레드에 대한 부분은 WAS가 처리
◦
개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 됨
◦
개발자는 마치 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드를 개발
◦
멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용
▪
공유 변수들은 멀티쓰레드에서 사용되면 안되기 때문에 조심해야한다.
구연지
1. 서블릿
•
이전에는 HTTP로 전송하기 위해 서버 연결, 소켓 연결, HTTP 파싱 등등 다양한 작업들을 직접 해주어야 했음
•
→ 실제로 중요한 비즈니스 로직에만 집중할 수 있도록 비즈니스 로직 외의 부분은 서블릿이 처리해 줌
2. 멀티 쓰레드
•
쓰레드가 하나인 경우 서블릿에서 요청을 하나 수행하고 있으면 다른 요청은 지연됨 → 멀티 쓰레드 사용
◦
(1) 하지만 요청이 올 때마다 쓰레드를 생성하면 응답 속도가 늦어진다: 쓰레드를 생성할 때 많은 비용이 소모된다
◦
(2) 코어보다 쓰레드 개수가 많은 경우 컨텍스트 스위칭 비용이 발생한다: 코어 1개에 1개의 쓰레드 대응된다
◦
(3) 쓰레드 생성에 제한이 없어 한계를 넘으면 서버가 죽을 수 있다.
→ 쓰레드 풀 사용
•
쓰레드 풀: 필요한 쓰레드를 미리 생성해서 쓰레드 풀에 넣고 관리한다: 최대치를 넘으면 대기하거나 거절한다
◦
(1) 해결: 쓰레드가 이미 생성되어 있어 시간이 단축된다.
◦
(3) 해결: 쓰레드의 최대치가 정해져 있어 많은 요청이 들어와도 안전하게 처리할 수 있다.
◦
WAS의 주요 튜닝 포인트는 최대 쓰레드 개수
▪
너무 낮으면 응답 지연, 너무 높으면 서버 다운
3. HTML API
•
HTML이 아니라 데이터를 전달: 주로 JSON 형식 사용
•
UI 클라이언트와 정보를 주고 받음
•
서버 사이에 통신을 할 때 사용하기도 함
4. 렌더링
•
SSR(서버 사이드 렌더링): 서버에서 최종 결과를 HTML로 만들어서 웹 브라우저에 전달 → 주로 정적인 화면
•
CSR(클라이언트 사이드 렌터링): HTML 결과를 자바 스크립트를 사용해 웹 브라우저에서 동적으로 생성해서 적용
◦
구글 캘린더, 네이버 지도와 같이 사용자가 필요한 부분을 변경할 수 있음
5. 자바 웹기술의 역사
서블릿: HTML 생성이 어려움
→ JSP: HTML 생성은 편리하지만 너무 많은 역할을 담당
→ 서블릿과 JSP를 이용한 MVC 패턴: 비즈니스 로직(서블릿)과 화면 렌더링(JSP)으로 나눔
→ MVC 프레임 워크 도입(MVC 패턴 자동화)
→ 어노테이션 기반의 MVC
→ Spring Boot: .jar에 WAS 서버가 포함되어 빌드 배포가 단순해짐
→ Web Servelet에는 Spring MVC, Web Reactive에는 Spring WebFlux(기술적 난이도가 높아서 실무에서 많이 사용하지는 않음)
•
뷰 템플릿(HRML을 편리하게 생성하는 기능)
JSP: 속도 느림, 기능 부족
→ 프리마커, 벨로시티: 속도 빠름, 다양한 기능, HTML의 모양과 다른 형태(사용하기 까달오ㅜㅁ
→ 타임리프: HTML의 모양을 유지하면서 뷰 템플릿 적용 가능(tag 이용), 스프링 MVC와 잘 맞음
6. HttpServeletRequest, HttpServeletResponse
1) HttpServeletRequest: HTTP 요청 메시지를 파싱하여 결과를 HttpServeletRequest 객체에 담아서 제공함
request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
// URL은 전체 주소, URI는 엔드포인트
request.getQueryString() = username=hello
// PathVariable로 넣어준 쿼리 스트링
request.isSecure() = false
Java
복사
•
request.getParameter() 는 파라미터의 이름이 하나일 때 사용, 여러개 일 때는 request.getParameterValues() 를 사용
•
HTML폼으로 데이터 전달하려면 꼭 content-type을 지정해주어야 함:application/x-www-form-urlencoded
◦
이처럼 특정 폼으로(ex. HTML 폼) 데이터를 전송하는 형식을 application/x-www-form-urlencoded 이라고 한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
HTML
복사
•
HTML message body에 데이터를 담아서 요청
◦
JSON, XML, TEXT 형식 (주로 JSON 사용)
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-bodyjson")
public class RequestBodyJsonServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData.username = " + helloData.getUsername());
System.out.println("helloData.age = " + helloData.getAge());
response.getWriter().write("ok");
}
Java
복사
2) HttpServeletResponse: HTTP 응답코드, 헤더, 바디 생성
•
content-type, 쿠키, redirect 등의 편의 기능을 제공하기도 함
•
응답 메시지의 형태
◦
단순 텍스트
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
writer.println("ok");
}
}
Java
복사
◦
HTML 형태 응답
@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
//Content-Type: text/html;charset=utf-8
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>안녕?</div>");
writer.println("</body>");
writer.println("</html>");
}
}
Java
복사
◦
message body에 담아서 응답: 주로 JSON 형태, content-type을 application/json으로 지정해야 함
@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
//Content-Type: application/json
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8");
HelloData data = new HelloData();
data.setUsername("kim");
data.setAge(20);
String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);
}
}
Java
복사
안지영
웹 서버란
웹은 http 프로토콜 기반 통신. 모든 형태의 데이터(HTML, TEXT, JSON, IMAGE, 영상, 파일)는 http 프로토콜을 기반으로 통신한다. 서버간의 데이터 주고 받을 때도 http를 사용한다.
웹 서버?
HTTP를 기반으로 동작하는 서버. 정적 리소스 제공. 특정 폴더에 파일을 두면 서버가 클라이언트의 요청에 따라 서빙을 해주는 것이다.
ex) Apache, NGINX
웹 어플리케이션 서버(WAS)?
•
HTTP를 기반으로 동작
•
웹 서버 기능 포함(정적 리소스 제공 가능) + 프로그램 코드를 실행해서 애플리케이션 로직 수행 가능
◦
웹 서버는 사용자마다 html을 다르게 보여주거나 할 수가 없는데, WAS 사용자에 따라 다른 화면을 보여 줄 수 있다. 프로그래밍을 할 수 있으니까.
•
동적 html을 생성할 수 있고, HTTP API 제공 가능
•
서블릿, JSP, 스프링 MVC가 WAS에서 동작
◦
ex) tomcat, jetty, Undertow
둘의 차이?
사실은 경계가 좀 모호하긴 하다. 웹 서버도 프로그램 실행하는 기능을 포함하기도 하고, 웹 어플리케이션 서버도 웹 서버의 기능을 제공한다.
→ 웹 서버는 정적 리소스 제공에, WAS는 애플리케이션 로직 처리에 더 중점을 둔다고 생각하면 될 듯.
웹 시스템 구성
WAS, DB만으로 시스템 구성이 가능하다.
→ 하지만 이러면 WAS가 너무 많은 일을 해서 과부하 가능성. 애플리케이션 로직은 html, css 등 파일들에 비해 비싸다. WAS가 만약에 죽으면 오류 화면조차도 보여줄 수가 없게된다.
그래서 일반적으로는 아래의 구조를 띈다.
WAS는 애플리케이션 로직에 집중할 수 있기 때문에 시스템 리소스를 효율적으로 쓸 수 있다.
서블릿
웹 어플리케이션 서버를 처음부터 모두 구현해야 한다면 HTTP 메세지를 처음부터 다 해석하는 것 부터 시작해야 한다. 소켓도 연결해야 하고, 단순히 텍스트 정보인 request를 파싱하여 많은 것을 읽어들어야 한다. 그 이후에야 비즈니스 로직을 실행하고 그 다음에 또 직접 HTTP response를 생성해야 한다. 전후 단계가 너무 많다.
서블릿은 비즈니스 로직 실행을 제외한 모든 기능을 자동으로 해준다.
URL이 호출되면 서블릿 코드가 실행된다. HTTP 요청/응답 정보를 편리하게 사용/제공할 수 있도록 각각 HttpServletRequests, HttpServletResponse 객체로 제공된다.
웹 브라우저에서 요청을 하면 WAS에서 요청 메세지를 기반으로 request, response 객체를 만든 후, 이를 파라미터로 넣어서 helloServlet을 실행해준다. helloServlet이 끝나고 return을 하면 WAS는 response 객체를 바탕으로 HTTP 응답메세지를 만들어 웹 브라우저에 전달하는 것.
서블릿 객체를 직접 생성하는게 아니라 코드만 만들면 서블릿을 지원하는 WAS내의 서블릿 컨테이너에 서블릿 객체를 서블릿 컨테이너가 자동으로 생성, 호출해주고 WAS가 종료될때 서블릿을 같이 종료해준다(생명 주기를 관리해준다).
톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다,
서블릿 객체를 싱글톤으로 관리한다. 객체를 하나만 생성해놓고 공유해서 쓰는 것이다. request, response 객체는 요청에 따라 다르므로 항상 새로 생성하는 게 맞지만, helloServlet은 그럴 필요가 없다. 재사용이 가능하다. (하지만 공유 변수를 사용할 때 주의해야 한다.) 서블릿 컨테이너 종료시 함께 종료된다.
쓰레드
서블릿 객체를 호출하는 것이 쓰레드이다. 애플리케이션 코드를 하나하나 순차적으로 실행하는 것이 쓰레드이다. 동시처리가 필요할 때는 쓰레드를 추가로 생성해주어야 한다.
하나의 쓰레드만 존재하고 다중요청이 들어올 경우: 만약 먼저 온 요청이 처리 지연 중이라면 두 요청 모두 처리되지 않고 오류가 발생할 것 → 신규 쓰레드를 생성하면 된다.
요청이 들어올 때 마다 새로운 쓰레드를 생성한다면?
쓰레드 풀
정해진 개수의 쓰레드를 만들어 놓고 갖다 쓰고 반납하는 것. 쓰레드 대기, 거절 가능
max thread 설정
너무 낮으면: 서버 리소스는 여유롭지만 클라이언트가 금방 응답 지연. CPU 사용률은 매우 낮고 서버만 늘리게 되는(비용 발생) 사태 발생할 수 있다,
너무 높으면: 동시 요청 많을 시 CPU, 메모리 리소스 초과로 서버가 다운될 수 있다.
튜닝 방법?
애플리케이션 로직 복잡도, CPU, 메모리, IO 리소스 상황에 따라 모두 다르다! DB를 한번 접근하는 것과 2번 접근하는 것은 무려 2배 차이이다.
→ 아파치 ab, 제이미터, nGrinder 등으로 성능 테스트
하지만 WAS가 멀티쓰레드에 대한 부분을 다 처리해준다.
마치 싱글 쓰레드인것 처럼 소스 코드를 개발하면 되지만, 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용해야 한다.
김재근
웹 - HTTP 기반
HTTP 메세지에 모든 것을 전송한다.
지금은 HTTP의 시대 !!!
•
HTML, TEXT
•
IMAGE, 음성, 영상, 파일
•
JSON, XML ( API )
•
거의 모든 형태의 데이터의 전송기능
•
서버간에 데이터를 주고 받을 때도 대부분 HTTP사용한다.
웹서버 (Web Server) - 정적인 페이지
•
HTTP 기반으로 동작한다.
•
정적 리소스를 제공 및 부가 기능을 한다.
•
웹서버의 예시 - Nginx, Apache
웹 어플리케이션 서버( WAS - Web Application Server ) - 동적인 페이지
•
HTTP 기반으로 동작한다.
•
웹서버의 기본적인 기능을 포함한다.
•
프로그램의 코드를 실행해서 특정 로직을 수행한다.
◦
동적 HTML, HTTP API( JSON )
◦
서블릿, JSP, 스프링 MVC
•
WAS의 예시
◦
Java Spring 진영 : 톰캣 ( Tomcat )
◦
Python Django/Flask 진영 : WSGI Server + Django/Flask
WebServer 와 Was의 차이점
최근 들어서는 둘의 용어 경계가 모호해졌다.
따라서 Web Server는 정적인 리소스 파일을 전달해주는 Server
Was는 Application을 로직을 실행해주는 Server 라 이해하면 된다.
클라이언트에서 이미지 좌측의 HTML Form 데이터를 전송한다 가정하겠습니다.
그렇게 되면 웹 브라우저에서 HTML 을 우측 이미지 처럼 HTTP 메세지로 전환한 뒤 서버에 전송하게 됩니다.
서블릿을 지원하지 않는 WAS 일 때
서버는 전송받은 데이터를 아래와 같은 로직으로 처리합니다.
•
서버 TCP / IP 연결 대기, 소켓 연결
•
HTTP 요청 메세지를 파싱 후 읽기
•
어떤 방식의 요청인지 확인 ( POST, GET, PUT, PATCH, DELETE ) , /save URL 인지 확인
•
Content - Type 확인
•
HTTP 메세지의 Body 내용 파싱
◦
(username, age 데이터를 사용할 수 있게)
•
저장 프로세스 실행 ( /save URL이라면 )
•
비즈니스 로직 실행 ( /save URL이라면 DB에 저장 요청 ) ← 의미 있는 비즈니스 로직
•
HTTP 응답 메세지 생성 시작
◦
HTTP 시작 라인 생성
◦
Header 생성
◦
메세지 Body에 HTML 생성에서 입력
•
TCP / IP 에 응답 전달, 소켓 종료
서블릿을 지원하는 WAS일 때
서블릿을 지원하는 WAS라면 비즈니스 로직만 개발자가 처리하면 됩니다.
•
서버 TCP / IP 연결 대기, 소켓 연결
•
HTTP 요청 메세지를 파싱 후 읽기
•
어떤 방식의 요청인지 확인 ( POST, GET, PUT, PATCH, DELETE ) , /save URL 인지 확인
•
Content - Type 확인
•
HTTP 메세지의 Body 내용 파싱
◦
(username, age 데이터를 사용할 수 있게)
•
저장 프로세스 실행 ( /save URL이라면 )
•
비즈니스 로직 실행 ( /save URL이라면 DB에 저장 요청 ) ← 의미 있는 비즈니스 로직
•
HTTP 응답 메세지 생성 시작
◦
HTTP 시작 라인 생성
◦
Header 생성
◦
메세지 Body에 HTML 생성에서 입력
•
TCP / IP 에 응답 전달, 소켓 종료
Servlet 의 특징
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) {
//애플리케이션 로직
}
}
Java
복사
•
urlPatterns(/hello) 의 URL이 호출되면 서블릿 코드가 실행됩니다.
•
HTTP의 요청, 응답을 편하게 사용할 수 있는 HttpsServletRequest, HttpServletResponse 가 있습니다.
•
개발자는 위 두가지를 이용해서 HTTP 스펙을 편리하게 사용할 수 있게됩니다.
•
하지만 개발자는 어떻게 데이터가 나가고 들어올 지 예상할 수 있어야 하기 때문에
HTTP의 스펙을 알아야 합니다.
HTTP 요청( Request ), 응답 ( Response )의 흐름
HTTP 요청시 WAS와 Servlet이 하는 일
•
WAS는 Request, Response 객체를 새로 만들어서 Sevlet 객체를 호출합니다.
•
개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용합니다.
•
개발자는 Resqonst 객체에 HTTP 응답 정보를 편리하게 입력합니다.
•
WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성합니다.
Servlet과 Servlet Container
•
Tomcat 과 같이 Servlet을 지원하는 WAS를 서블릿 컨테이너 ( Servlet Container )라고 합니다.
•
서블릿 컨테이너는 서블릿 객체를 생성, 초기화 호출, 종료하는 생명주기를 관리해줍니다.
•
서블릿 객체는 싱글톤으로 관리됩니다.
싱글톤으로 관리되는 이유는 다음과 같습니다.
◦
고객의 요청이 들어 올 때 마다 서블릿 객체를 계속해서 생성하는 것은 비효율 적입니다.
◦
최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용 합니다.
◦
모든 고객의 요청은 동일한 서블릿 객체 인스턴스로 접근합니다.
( 공유 변수 사용에 주의해야 합니다. )
◦
서블릿 컨테이너 종료시 함께 종료됩니다.
•
JSP 또한 서블릿으로 변환되서 사용됩니다.
•
동시 요청을 위해서 멀티 쓰레드 처리를 지원합니다.
[어려웠던 부분]
•
딱히 어려웠던 부분보다는 몰랐던 것을 알게되는 시간이였다.
Plain Text
복사
•
배웠던 내용을 좀 더 꼼꼼하게 정리하는 시간이었다.
Plain Text
복사
•
서블릿 컨테이너, 서블릿, WAS 세 개를 구분하는 게 좀 어려운 것 같다.
Plain Text
복사
•
서블릿은 듣기만 했지 개념에 대해서는 처음 듣게 되어서 아직 낯선것 같다ㅠ
Java
복사
[금주의 꿀팁 & 인사이트!]
•
서블릿에대해 자세히 몰랐는데, 개발자가 비지니스 로직에만 집중할 수 있게 도와주는 것이라는것을
알게 되었다.
이를 통해 왜 MVC패턴이 나오게 되었는지도 알게되어 좋았다.
Plain Text
복사
•
꿀팁...은 아직 없는 것 같고 기초를 다질 수 있는 시간이어서 좋은 것 같다 :)
Plain Text
복사
•
아직까지도 어쩌면 웹 서버에 대해 잘 몰랐던게 아닐까 싶었다!
Plain Text
복사
•
서블릿에 대해 알게되어서 좋았고 알고 있던 지식들도 다시 다져갈 수 있어서 좋았다!
Java
복사
[금주의 느낀 점]
•
확실히 기본 개념들을 확실히 알고있는것과 모르고 있는것의 차이는 엄청난거같다.
꾸준히 복습하고 진도를 나가서 CS개념을 잘 숙지하도록 하자.
Plain Text
복사
•
배웠던 내용을 꼭 한 번 복습을 해야할 것 같다. 나중에 면접에서 질문하시면... 답변하기 힘들지 않을까 ㅠㅠ
Plain Text
복사
•
좀 더 단순한 것 부터 구현해보는 게 장점이라는 생각이 들었다. 오히려 기본적인 것을 하다 보니
큰 그림을 이해하는 데 더 도움이 된 것 같다.
Plain Text
복사
•
간단하게 기본적으로 백엔드 엔지니어가 왜
Java
복사