우리는 일단 client와 client, client와 서버 모든것을 HTTP를 기반으로 통신한다.
간단하게 HTTP가 뭐냐면, 뭐 client와 서버끼리 무언가 주고받고싶다고 치자, 그러면 client가 전달한 무언가를 보고 서버가 해석을 할 수 있어야 어떤 비즈니스 로직을 처리 할 수 있을것아닌가?
이때, 어떻게 요청과 응답을 받을지 서로 인터넷상에서 데이터를 주고받을 수 있는 규약,프로토콜을 HTTP라고한다.
자세한 HTTP에 대한 것은 CS-컴퓨터네트워크 파트에서 설명할 것이므로, 넘어가도록 하고,
어쨋든 우리는 HTML,TEXT,IMAGE,음성,영상,파일,JSON,XML 등등 모든것을 HTTP메세지에 전송한다.
웹서버
http 기반으로 동작
정적 리소스 제공
정적파일 HTML,CSS,JS,이미지,영상 제공
웹 애플리케이션 서버
http 기반으로 동작
웹서버 기능 포함 + 정적 리소스 제공
프로그램 코드를 실행해서 애플리케이션 로직 수행--동적 HTML,HTTP API,서블릿,JSP,스프링 MVC등등
웹 서버 vs 웹 애플리케이션 서버 (WAS)
웹서버는 정적 리소스, WAS는 애플리케이션 로직
WAS는 애플리케이션 코드를 실행하는데 특화
웹 시스템 구성
WAS,DB만으로도 시스템 구성가능
why? was는 정적리소스, 애플리케이션 로직 모두 제공이 가능하니까.
그런데 이러면, was가 너무 많은 역할을 담당
정적리소스 때문에, 애플리케이션 로직이 수행이 안될 수 있음
심지어 was가 죽어버리면 장애시 오류화면도 노출 불가능
웹 시스템 구성 - web,was,db
정적리소스-web 서버가 처리
if 동적인 처리가 필요하면 web서버가 was에게 요청을 위임
was는 중요한 애플리케이션 로직 처리에 전담할 수 있음
이렇게 분리하면 좋은점이 정적리소스가 많이 사용되면 web서버 증설, 애플리케이셔 리소스가 많이 사용되면 was증설등, 효율적인 리소스 관리 가능
또한, was가 죽어버리면, web서버는 살아있으므로, 오류화면 HTML 노출가능
서블릿이 무엇일까? 아니다 서블릿보다 처음부터 생각을 해보자
만약에 localhost:8080/api/hello라는 주소로 클라이언트가 요청을 웹서버로 보냈다고 치자.
그러면, 아까 위의 그림처엄 클라이언트가 웹서버에 요청을 하게 되면, 웹서버는 그 요청을 톰캣과 같은 WAS에 요청을 위임한다.
그러면, WAS는 각 요청에 해당하는 서블릿을 실행한다. 그리고 서블릿은 요청에 대한 기능을 수행한 후 결과를 반환하여 클라이언트에게 전송한다.
잉? 갑자기 서블릿을 실행한다고?
일단 이전에 입문,기본편 포스트를 봤다면, 서블릿을 일단은! MVC에서 컨트롤러라고 생각을 해보자.
내가 어떤 /api/hello라는 url로 요청을 보냈고, 그렇다면 이 url에 해당하는 컨트롤러가 MVC프레임 워크에서는 있을 것이다.
고로, 클라이언트가 요청을 보내면, HttpServletRequest,HttpServletResponse객체를 생성한다.
이러면 이걸 가지고 request.get어쩌구로 쉽게 가져올수 있다.
그다음에 Web.xml이 어느 서블릿에 대해 요청한것인지 탐색한다.->URL을 보고 어떤 서블릿에 해당하는 URL인지 확인한다.
그다음에 해당하는 서블릿에서 service()메서드를 호출한다. 여기 해당 서블릿에는 init과 destory도 있다.
그다음에 doGet,doPost같은 요청한 메서드를 실행하고, 그결과를 바탕으로 동적 페이지를 생성후 ServletResponse객체에 넣은다음에, 이 Response객체를 전송하고
마지막으로 HttpServletRequest,HttpServletResponse 객체가 소멸된다.
이러한 일련의 과정은 우리는 MVC 프레임워크를 사용하면서 어떤놈?이 대신 해준것이다.
다시 그림을 봐보자
그림에서 보면, request,response객체가 요청을 보낸 http 요청메시지 기반으로 생성한후
이걸 파라미터로 넘기면서, 서블릿컨테이너에서, 실행한다.
서블릿 컨테이너란, 서블릿들을 모아 놓은것이다.
쉽게 표현하자면, /api/hello 서블릿 /api/donghyun 서블릿 이것들을 모아놓은다음에
여기 컨테이너에서 해당 URL을 바탕으로 서블릿을 찾아서 실행을 시키고 response객체에다가 담은뒤에 응답하고 이 response,request객체를 소멸시키는 일련의 과정이 있는것이다.
그리고 이 모든 WAS를 관장하는 것을 톰캣 서버라고하는데 apache tomcat이다.
또한 WAS에 있는 서블릿 컨테이너가 서블릿 객체의 생성, 호출 ,관리를 담당해준다.
결국 우리는 서블릿을 지원하는 WAS를 사용하지 않는다면,
-> 서버 TCP/IP 핸드쉐이킹, 소켓 연결
-> Http요청 메시지를 파싱해서 읽기
-> post방식인지 get방식인지 구분
-> URL 인식
-> Content-Type확인
-> HTTP 메시지 바디 내용 파싱
-> 저장 프로세스 실행
-> 비즈니스 로직 실행 ★
-> DB저장 요청 ★
-> HTTP 응답 메시지 생성 시작
-> Header생성
-> 메시지 바디에 HTML생성해서 입력
-> TCP/IP에 응답 전달, 소켓종료
이런식으로 우리는 별표시 친 비즈니스 로직만 실행하고 싶은데, 실제로 이 모든 코드를 개발자가 일일히 작성해야만한다.
그런데 서블릿을 지원하는 WAS를 사용하면, 우리는 비즈니스 로직만 짜면되고, 뭐 핸드쉐이크부터 http메세지 파싱 뭐 또 서블릿 부르고 로직 처리하고 이런 과정을 일체 하지 않아도 된다.
실제로 우리가 controller 코드 짤때 이걸 스프링 컨테이너에 등록하는것도 어노테이션 하나 띡 붙이면 되고, 이걸 뭐 서블릿에 등록하거나, 또는 init destory, 컨트롤러에서 어떤 url 메서드를 실행할것인지 컨트롤러 내에서 메서드들을 뒤져서 매핑하는 이런 코드는 일체 작성하지 않았다.
이것을 Spring이 대신 해주는것 같습니다.. 이걸 Spring이 해준다고 이해를 하는게 맞는지는 모르겠습니다..ㅠ 다음에 더 깊게 공부해서 새로운 포스트로 찾아 뵙겠습니다.
여담으로, 서블릿에 대해서 궁금해서 구글링을하다가,,, 너무 많은 내용이 있고,, 아직도 모르는게 이렇게 많다는 자괴감이...ㅠㅠ
저는 결국 궁금증이 spring이 그럼 서블릿을 사용하는건가?
서블릿 컨테이너랑 스프링 컨테이너 차이가 뭔가?
서블릿 컨테이너를 스프링 컨테이너라고 생각하는게 맞는건가?
등등 너무나도 많은 양의 질문과 포스트들을 봤는데 하나도 이해가 가지않는.. 자괴감 + 새로운것을 배울게 이렇게 많다는 두근거림이 들었네요..
여기 진짜 좋은글과 영상이 있어서 링크 남길테니 따로 공부를 해보시길..
servlet container vs spring container
servlet vs spring--우아한 테크톡
만약 클라이언트가 요청을 보내면 was와 연결한 뒤에, 해당 요청에 맞는 서블릿 객체를 호출 해줄 것이다.
그러면, 서블릿 객체를 누가 호출 해주느냐?->쓰레드가 호출을 해준다.
쓰레드에 관한 내용은 OS포스팅에 있으니 읽어보길 바란다.
운영체제-프로세스편
어쨋든, 단일 프로세스라고 생각을 해보면
이런식으로 쓰레드를 만들고 연결해서 해당 서블릿을 호출하면 될것이다.
응답하고
서블릿은 휴식하면 된다.
근데 문제는 다중 요청인데 쓰레드가 하나 있는 경우이다.
요청이 들어와서 쓰레드가 요청 1을 수행하고있는데, 만약 서블릿 처리가 지연되고 있다고 가정하자.
어떤 악성 개발자가 delay를 걸어놨을 수도 있고, DB를 뒤져서 가져오는데도 오래 걸릴 수도 있다.
그러면 요청2는 이 쓰레드가 빨리 요청1을 처리하고 내것을 처리해주길 기다리다가, 결국 둘다 죽는것이다.
그럼 어떻게 해야할까? 바로 요청마다 쓰레드를 생성하는것이다.
그러면 요청1의 서블릿 처리가 지연되더라도, 요청2는 수행이 가능 할 것이다.
장점
동시요청을 처리 할 수 있다.
하나의 쓰레드가 지연되어도, 나머지 쓰레드는 정상 작동하낟.
단점
쓰레드 생성비용은 매우 비싸다.
고객의 요청이 올때마다, 쓰레드를 생성한다면, 응답속도가 늦어질 수 밖에 없다.
쓰레드는 컨텍스트 스위칭 비용이 발생한다.
위의 OS글을 읽어보면 알 수 있는데, 간단히 설명하자면, 쓰레드가 1개일때는 상관없겠지만, 쓰레드가 여러개라면, CPU는 한번에 하나의 작업밖에 수행을 하지 못한다.
그래서 쓰레드 1개를 처리하다가, timerInterrupt가 걸린다던지 IO를 해야한다던지 이러면 다른 쓰레드를 처리해줘야하는데
이때 쓰레드->다른쓰레드로 넘어갈때 컨텍스트 스위칭이라고 한다.
그전까지 하던 내용들을 저장해야하므로, 비용이 발생한다.
쓰레드 생성에 제한이 없다.->너무 많은 고객요청이 발생하면, cpu,메모리 임계점을 넘어서 서버가 죽을 수 있다.
해결법
그래서 우리는 쓰레드 풀을 만들어서 관리한다.
WAS를 띄울때, 쓰레드를 대략 200개정도 만들어 넣고, 서버를 띄우는것이다.
만약에 요청1,2가 들어오면 쓰레드풀에서 2개를 가져다가 쓰고, 쓰레드를 지우는게 아니라 쓰레드 풀에 반납을 한다. 만약에 200개를 다쓰면, 쓰레드 대기 혹은 거절을 한다.
쓰레드풀
특징
필요한 쓰레드를 쓰레드 풀에 넣고 관리하낟.
쓰레드 풀에 생성 가능한 최대치를 관리한다. 톰캣은 최대 200개 설정 가능
사용
쓰레드가 필요하면, 이미 생성되어있는 쓰레드를 쓰레드 풀에서 꺼내서 사용한다.
사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납한다.
최대 쓰레드가 모두 사용중이어서 쓰레드 풀에 쓰레드가 없으면, 기다리는 요청은 거절하거나, 특정 숫자만큼 대기하도록 설정이 가능하다.
장점
쓰레드가 미리 생성되어 있으므로, 쓰레드를 생성하고 종료하는 비용이 절약되고, 응답 시간이 빠르다.
생성 가능한 쓰레드의 최대치가 있으므로, 너무 많은 요청이 들어오더라도, 기존 요청은 안전하게 처리가 가능하다.
팁
was의 주요 튜닝 포인트는 최대 쓰레드 수이다.
너무 낮게 설정하면, 서버는 여유롭지만, 클라이언트는 응답 지연이되고
너무 많이 설정하면, 동시 요청이 많아지면, cpu와 메모리 임계점 초과로 서버가 죽어버린다.
만약에 내가 쓰레드 최대를 50으로 했다고 치자, 그런데 고객 요청이 너무 한꺼번에 많이 들어와서 응답지연이 걸리자,
서버 증설을 하나 더했다.
그러면 이제 각각 50 + 50 으로 100개의 쓰레드를 처리 할 수 있게 되었다.
그러나, 굳이 서버를 하나 더 늘리지 않고 50개에서 100개로 늘리기만 하여도, 서버 증설을 하는 쌩돈을 날리지 않을 수 있는것이다.
그래서, 개발자는 쓰레드 최대치를 조절하는게 살짝 어렵다.
왜냐하면, 너무 많이하면, 서버가 죽어버리고, 너무 적게하면, 쓰레드 처리량이 너무적고 이런 고착에 빠지는것이다.
그래서 이런 쓰레드 풀의 적정 숫자를 찾으려면,
애플리케이션 로직의 복잡도, CPU, 메모리, IO리소스 상황에 따라 구분지어서 해결해야한다.
성능테스트툴: 아파치 ab,제이미터,nGrinder
WAS의 멀티 쓰레드 지원의 핵심
그런데 입문편과 기본편을 수행하면서 WAS의 멀티 쓰레드 설정같은것을 해본적이 있나?
없다.
왜냐하면 멀티 쓰레드에 관한 부분은 WAS가 처리해주기 때문이다.
고로 개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 된다.-> 예를 들어, 여러명의 클라이언트가 서블릿으로 요청을 보낼시 어떻게 처리할지 이런코드 같은걸, 작성을 우리가 하지도 않았고, 할 필요도없다.
마치 우리는 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드 개발을 하면된다.
우리는 그러나 약간의 중요한 부분만 생각하면된다, 멀티 쓰레드 풀 최대치 설정이나, 멀티 쓰레드 환경이므로 싱글톤 객체를 주의해서 사용하는 이런것들을 생각하면된다.
정적리소스
고정된 HTML 파일, CSS,JS,이미지,영상등을 제공한다.
HTML 페이지
동적으로 필요한 HTML 파일을 생성해서 전달한다.
요청이 들어오면->WAS에서 ->DB로 정보들을 가져온다음에 ->이 정보를 바탕으로 HTML 생성->JSP,타임리프만들고 -> HTML 반환
HTTP API
HTML이 아니라 데이터를 전달, 특히 JSON형식
요청이 들어오면->WAS에서 ->DB로 정보들을 가져온다음에->JSON{"주문번호":100,"금액":5000}을 전달
다양한 시스템에서 호출된다,
데이터만 주고받는다, 만약 UI 화면이 필요하면, 클라이언트가 별도 처리한다.
만약에 앱 클라이언트 to 서버 로 HTTP API 통신을 한다고 가정해보자, 근데, 사실 앱 컴포넌트로 정보만 주면, 알아서 그려서 반환해주니까,
그냥 우리는 JSON형식으로 data만 넘겨주면 된다.
SSR-서버사이드 렌더링
HTML 최종결과를 서버에서 만들어서 웹 브라우저에 전달.
주로 정적인 화면에 사용
CSR- 클라이언트 사이드 렌더링
HTML 결과를 자바스크립트를 사용해 웹 브라우저에서 동적으로 생성해서 적용
실제로 구글 맵 같은게, 우리가 지도를 이동시키거나, 늘리거나 줄여도, URL이 바뀌고 그런게 아니라, 그 상태에서 필요한 부분부분 변경 된다,
주로 동적인 화면에서 생성해서 UI에 적용 가능하다.