우리가 만든 건 웹 서버가 아니다!
우리는 열심히 서버 개발을 해서 사용자가 원하는 서버를 만든다. 하지만 이건 Web Server 가 아니다!
Web Server는 단순하게 "웹 페이지를 위한 서버"를 뜻하는 말로 복잡한 뭔가를 하지 않는다고 받아들이면 될 것 같다.
우리가 열심히 코딩해서 만든 서버는 WAS, Web Application Server 이다. 단순한 Web Server가 아니라 Application이 들어갔다.
그럼 Web Server는 도대체 뭘까..?
Web Server
Web Server는 Apache, NginX로 대표되며, static page를 다루는 서버이다. 경로에 따라서 항상 같은 페이지를 반환한다는 의미이다. 예를 들어서 밑의 사진과 같이 Apache를 설치하면 나오는 기본적인 page가 static page이다.
사용자에 따라서 상황에 따라서 로직을 수행하지 못하고 정적인 컨텐츠만 다룰 수 있는 것이 Web Server이다. 예를 들어 회사 홈페이지에서 회사 소개 페이지를 전달할 때는 복잡한 로직이 필요없으니 Web Server로 충분하다.
Web Server는 2가지 일을 한다. (사실상 같은 일이지만 나눠서 생각해보자.)
- 위에서 말한 것처럼 정적 콘텐츠를 제공하는 일.
- 뒤에 있는 WAS에게 요청해 동적으로 생성된 콘텐츠를 응답해주는 일.
사실상 2번은 왜 있는지 이유를 당장은 모르겠다. 그냥 WAS가 하면 되기 때문이다. 이걸 알아보기 전에 일단 WAS에 대해 알아보자.
WAS (Web Application Server)
WAS는 Tomcat 서버로 대표되며, 로직을 통해 동적인 컨텐츠를 다룰 수 있다. 우리가 사용하는 서비스의 서버에는 모두 WAS가 있다고 생각하면 된다.
WAS는 HTTP를 통해 컴퓨터나 장치에 애플리케이션을 수행해주는 미들웨어(소프트웨어 엔진)이다.
내부적으로 웹 서버와 웹 컨테이너를 포함한다. 웹 서버는 위에서 설명한 그것이고, 웹 컨테이너는 Servlet, JSP 등을 실행시킬 수 있는 구동환경을 제공해준다. 사실상 WAS의 존재 이유가 웹 컨테이너이므로 WAS를 그냥 "웹 컨테이너", "서블릿 컨테이너" 라고 부르기도 한다.
WAS 안에 웹 서버가 있으므로 정적 콘텐츠도 제공해줄 수 있고, 현재의 Tomcat은 Apache나 NginX에 비해 정적 콘텐츠 제공 속도도 느리지 않다.
그럼 도대체 Web Server는 왜 필요할까
Web Server의 역할
Web Server가 하는 역할을 보자.
- 단순한 정적 컨텐츠 제공
- 무중단 배포
- Reverse Proxy
- Load Balancer
- 보안
단순한 정적 컨텐츠 제공
WAS는 다양한 로직을 처리하느라 바쁘다. 단순한 정적 컨텐츠는 Apache 혹은 NginX 같은 Web Server가 먼저 처리해주면 WAS까지 요청이 가지 않아 서버 부하가 방지된다.
여러 대의 WAS가 필요한 경우
사용자가 많으면 로직을 처리하는 WAS를 여러 대 두어야 할 필요가 있다. 예를 들면 8080 포트로 하나의 WAS, 8081 포트로 하나의 WAS를 배포하는 것이다. 이럴 때, Web Server가 두 개의 WAS에 요청을 분산시켜 보낸다. 바로 Load Balancer 의 역할을 하는 것이다.
이 때, Web Server는 비정상적으로 동작하는 WAS를 판별하기 위해 WAS 들에게 health check 신호를 날릴 수 있다. 만약 제대로 동작하지 않는다면, 해당 WAS에게 요청하지 않고, 다시 돌아올 때까지 기다린다.
또한, 무중단 배포(Rolling, Blue Green, Canary)에 필요할 수 있다. 여러 대의 WAS가 있으면, 이 중 일부의 WAS에 신버전을 배포하고 점진적으로 모든 WAS에 신버전을 배포한다. 자세한 내용은 아래를 참고하자.
보안
실제 WAS를 클라이언트에게 노출하지 않는다. 예를 들면 포트 번호 같은 것들도 모두 WAS의 설정 사항이다. 이런 것들을 숨기고 Web Server만 노출한다.
Apache vs NginX
Web Server는 Apache와 NginX로 대표된다. 기존에 대표적인 Web Server는 Apache였다. 하지만 갈수록 NginX를 더 많이 쓴다.
Apache
Apache는 프로세스 기반 접근 방식이다. 미리 프로세스를 만들어놓고 새로운 요청이 들어올 때마다 만들어진 프로세스에 대해 connection을 생성한다. 이 때, connection 생성/종료에는 3-way-handshake 등의 복잡한 과정이 필요해 비용이 크다. HTTP 1.1에 나온 keep-alive 헤더 덕분에 어느 정도 해결됐지만, 컴퓨터의 보급이 빨라지고 요청이 많아지자 유지되는 connection 수가 많은 것도 부담이 되었다. 10000 단위가 넘어가면 connection 연결에 문제가 생겼는데, 이것을 C10K 문제 (Connection 10000) 라고 한다.
이런 방식은 Apache의 방법 중 Prefork 방식이다. Worker 방식은 이 방식이 문제가 되자 나온 방법이지만, 성능상 뒤에 나올 NginX가 훨씬 좋다.
즉, 미리 프로세스를 만들어놓고, 커넥션이 빈번하게 발생되어 문제가 발생하는 것이 문제라는 것. 한 마디로, 너무 무겁다는 것이다.
NginX
NginX는 이벤트 기반 접근 방식이다. Master Process가 만들어 놓은 Core 개수 만큼의 Worker Process가 있다. 어떤 프로세스에 connection 요청이 들어오면 connection을 맺고 일을 하는 건 똑같다.
하지만, connection 요청, connection 해제, 그리고 각각의 일들을 하나의 "이벤트"로 보고 이벤트들을 관리한다. 즉 여러 개의 connection을 맺고 있을 수 있는 것이다. 특히, I/O와 관련된 많은 일들을 Thread Pool 로 관리하고 일을 해서 빠르다.
Apache는 프로세스가 담당하는 일을 바꾸는 Context Switching 이 너무 많이 일어났다. NginX는 이벤트 기반으로 관리하기 때문에 Context Switching이 현저히 줄어든다.
어떤 걸 써야 할까?
당연히 NginX를 써야 할 것 같지만, 그건 아니다.
Apache는 무겁지만 모듈이 다양하고 안전성, 확장성, 호환성이 우세하다. 또한 대규모 커뮤니티가 있어서 문제를 탐색하기도 쉽다. 특히 옛날에 만들어진 버그가 많은 페이지는 Apache를 써야만 하는 경우가 많다.
만약 요즘 Web Server를 기용한다면 NginX를 많이 쓴다. 방금 전 언급한 문제가 없다면 가볍고 빠르기 때문이다.
참고
https://www.youtube.com/watch?v=mcnJcjbfjrs
https://www.youtube.com/watch?v=Zimhvf2B7Es
https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html