트래픽이 많은 웹사이트의 서버(WAS)를 도와주는 비동기 이벤트 기반구조의 웹 서버 프로그램이다.
공식문서에서는 "NGINX는 고성능, 확장성, 고가용성 웹서버, 역방향 프록시 서버 및 웹 가속기(HTTP 로드밸런서, 콘텐츠 캐시 등의 기능 결합)이다." 라고 소개하고 있다.
Web Server : 단순히 정적 파일 응답 (정적파일 : HTML, CSS, JS, 이미지, 영상)
예) NGINX, APACHE
WAS(Web Application Server) : 클라이언트 요청에 대해 동적 처리가 이뤄진 후 응답
예) 톰캣(Tomcat) Jetty, Undertow
리버스 프록시는 외부에 노출시키려는 리소스 앞 단에 위치한다. 리버스 프록시를 수행하는 Nginx의 역할은 다음 그림과 같다.
Forward Proxy
Reverse Proxy
대부분의 WAS 는 Web Server 기능을 제공하므로 Reverse proxy 가 없이 내부 WAS 가 직접 서비스를 제공해도 되지만 이렇게 구성하는 이유중 여러가지가 있다.
리버스 프록시의 웹서버를 리소스의 앞 단에 위치 시킴으로, DB와 연결된 WAS의 보안을 강화 할 수 있다.
Cache Server 를 붙이거나 SSL 하드웨어 가속기를 연동하는등 아키텍처 측면에서 성능 향상을 하기가 해진다.
리버시 프락시를 cluster로 구성해 놓으면 가용성을 높일 수 있고 사용자가 증가하는 상황에 맞게 Web Server 나 WAS 를 유연하게 늘릴 수 있는 장점이 있다
리버스 프록시 환경을 통해 구축 및 쉽고 저렴하게 무중단 배포를 구축할 수 있다.
웹 시스템의 구성
WAS는 정적 리소스, 애플리케이션 로직 모두 제공 가능해서 WAS, DB 만으로 시스템 구성 가능하다.
하지만 WAS가 너무 많은 역할을 담당하면, 서버 과부하 우려가 있고 가장 비싼 애플리케이션 로직이 정적 리소스 때문에 수행이 어려울 수 있음
또한, WAS 장애시 오류 화면도 노출 불가능하다.
따라서 요즘은 정적 리소스는 웹 서버가 처리하고, 애플리케이션 로직같은 동적인 처리가 필요하면 웹서버가 WAS에 요청을 위임하여 WAS는 중요한 애플리케이션 로직 처리 전담하는 프로세스로 구성.
이렇게 구현하면 또다른 장점은 정적 리소스만 제공하는 웹 서버는 잘 죽지 않고 애플리케이션 로직이 동작하는 WAS 서버는 잘 죽음으로( 보통 잘못된 코딩으로 개발자의 실수) WAS, DB 장애시 WEB 서버가 오류 화면을 제공할 수 있다.
// 비교방식으로 설명, 왜 쓰는지 중점, 둘 중에 뭐가 좋다기보다는 이럴때 뭐가 좋다. 라고 말할수 있어야함
둘이 출시 됐을때 인터넷 상황을 보면 NGINX가 이렇게 많은기능을 담당하고 있고 웹서버 분야에서 1등을 하고 있는지 알 수 있다.
유닉스 기반 최초의 웹서버
버그가 굉장히 많아 개발자들이 사용하는데 불편함이 많았다.
버그 수정하고 구조 변경하고 기능도 추가해서 개발된것이 아파치 서버다
아파치 서버 구조
아파치 서버는 요청이 들어오면 커넥션을 형성하기 위해 프로세스를 생성한다.
(이는 유닉스 계열 OS가 네트워크 커넥션을 형성하는 모델을 그대로 적용한 것이다.)
프로세스 생성 시간이 오래 걸리므로 요청이 들어오기 전에 프로세스를 미리 생성하는 PREFORK 방식을 사용했다.
그래서 새로운 클라이언트 요청이 들어오면 미리 만들어 놓은 프로세스를 가져다 사용했다.
만약 만들어 놓은 프로세스가 모두 할당되면 추가로 프로세스를 만들었다.
아파치 서버 장점 : 이런 구조는 개발하기 쉽다는 장점이 있었다.(확장성)
아파치 서버 장점 : 덕분에 개발자는 다양한 모듈을 만들어서 서버에 빠르게 기능을 추가할 수 있었다.
나온지 1년도 안되서 1위가 된다.
이 시기는 인터넷 트래픽이 계속해서 증가하는 시점이였다.
서버가 처리해야 할 요청 양이 당시 기술로 감당가능한 정도였는데 점점 컴퓨터가 많이 보급되고 요청이 많아지면서 서버에 이상한 문제가 생긴다.
서버에 동시에 연결된 커넥션이 많아졌을때 더 이상 커넥션을 형성하지 못하는 문제가 생겼다. = C10K 문제(Connection 10000개의 문제)
C10K 문제는 NGINX가 생기는 원인이 된다.
초당요청 처리수 = 서버가 얼마나 빨리 요청을 처리할 수 있는지 나타내는 지표
동시에 연결된 커넥션 수 = 요청을 처리하기 위해 서버가 얼마나 많은 클라이언트와 커넥션을 형성하고 있는지 나타내는 지표
각 요청마다 매번 커넥션을 만들기에는 비효율적이고 속도도 느렸다.
그래서 사람들은 요청을 보낼때 이미 만들어진 커넥션이 있다면 그것을 재활용하자는 생각을 한다.
그런데 클라이언트 수가 많아지면 그만큼 동시에 연결되어 있는 커넥션 수는 더더욱 많아진다.
아파치 서버 단점 : 그렇게 동시 커넥션수가 만 단위가 넘어가는 순간 서버는 더 이상 커넥션을 형성하지 못하는 상황이 온다.
문제의 원인은 컴퓨터의 하드웨어 측면이 아닌 아파치 서버나 그외 대다수 서버의 구조 였다.
요청이 많아지면 (문제점)
수 많은 동시 커넥션을 감당하기에는 아파치 서버의 구조가 적합하지 않았다.
이러한 한계들을 극복하기 위해 다양한 시도를 하게 됨
새로운 구조를 채택하면서 아파치 서버를 보완하기 위한 소프트웨어가 나오는데 이게 바로 NGINX다.
초창기 엔진엑스는 아파치서버와 함께 사용되기 위해 만들어졌다. 웹서버지만 아파치 서버를 완전히 대체할 목적은 아니였다. 아파치 서버가 가진 구조적 한계를 엔진엑스를 사용해서 극복하려 했다.
아파치 서버 앞단에 엔진엑스를 둡니다
NGINX와 APACHE를 같이 씀
이렇게 하면 기존에 아파치 서버가 감당해야 했던 수 많은 동시 커넥션을 엔진엑스가 대신해서 유지 할 수 있다.
엔진엑스는 웹서버라 정적파일(HTML, CSS, JS, 이미지, 영상)에 대한 요청은 스스로 처리할 수 있다.
클라이언트로부터 동적 파일 요청을 받았을 때만 뒤에 있는 서버와 커넥션을 형성한다.
아파치 서버의 리소스를 커넥션 유지에 쓰지 않고 개발자가 원하는 로직처리에 쓰도록 도와주는것임
그러면 엔진엑스는 어떤 구조로 되어있길래 그 많은 동시 커넥션을 유지할 수 있을까?
비결은 만들어지는 프로세스 수에 있다.
엔진엑스는 마스터 프로세스가 있고 설정파일을 읽고 설정파일에 맞게 워커 프로세스를 생성하는 프로세스이다.
이 워커 프로세스가 실제로 일을 하는 놈이다. 워커프로세스가 만들어질때 지정된 listen소켓을 배정받는다.
그 소켓에 새로운 클라이언트로 부터 요청을 들어오면 커넥션을 형성하고 그 요청을 처리합니다. 그러고 나면 그 커넥션은 정해진 keep-alive시간만큼 유지가 된다.
그런데 커넥션이 형성되었다고 해서 워커 프로세스가 해당 커넥션 하나만 한정적으로 담당하지는 않는다. 형성된 커넥션에 아무런 요청이 없으면 새로운 커넥션을 형성하거나 이미 만들어진 다른 커넥션으로 부터 들어온 요청을 처리한다.
엔진엑스에서는 이런 커넥션 형성, 제거 그리고 새로운 요청을 처리하는 것을 이벤트라고 부른다.
그리고 그 이벤트들은 OS커널이 큐 형식으로 워커 프로세스에게 전달해 줍니다.
이 이벤트는 큐에 담긴 상태에서 워커 프로세스가 처리할 때까지 비동기 방식으로 대기해요 그리고 워커 프로세스는 하나의 스레드로 이벤트를 처리해 나가죠
네모칸이 큐인데 안에 보면 커넥션을 생성하거나 요청을 처리하는 이벤트로 채워져 있는 것을 볼 수 있어요.
이러면 워커 프로세스가 쉬지 않고 계속해서 일을 한다는 장점이 있어요
아파치 서버 구조와 비교를 했을때 요청이 없다면 방치되던 프로세스보다 서버자원은 훨씬 효율적으로 쓰는 셈이죠
그런데 여기서 이런 질문이 생길 수 있다. 만약 이 요청중 하나가 시간이 오래걸리는 작업이라면 어떻게 해야 할까? 예를 들어 Disk에 읽고 쓰는 작업을 해야한다면 그 뒤에 있는 이벤트는 요청을 처리하는 긴 시간동안 블로킹이 되겠죠
엔진엑스는 이런 상황을 방지하기 위해 그렇게 시간이 오래걸리는 작업을 따로 수행하는 쓰레드 풀을 만든다.
그리고 워커 프로세스는 지금 처리할 요청이 시간이 오래 걸릴거 같다 싶으면 해당 스레드 풀에 그 이벤트를 위임하고 큐 안에 있는 다른 이벤트를 처리하러 간다.
이런 워커 프로세스는 보통 cpu의 코어 수 만큼 생성한다.
이러면 코어가 담당하는 프로세스를 바꾸는 횟수를 대폭 줄일 수 있어요 cpu가 굳이 부가적인 일을 하지 않아도 되는거죠
다시말해 cpu의 컨텍스트 스위칭 사용을 줄이는 거에요
이게 바로 엔진엑스가 채택한 Event-Driven Model(이벤트 기반 구조)이고 아파치 서버와 가장 큰 차이점이다.
엔진엑스 구조의 단점
개발자가 기능추가를 시도했다가 돌아가고 있는 워커 프로세스를 종료하게 되는 상황이 생길 수 있는 건데요
그러면 해당 워커 프로세스가 관리하고 있던 커넥션과 관련된 요청을 더이상 처리할 수 없게 되는 문제가 발생한다.
그래서 엔진엑스는 개발자가 직접 모듈을 만들기가 까다로워요 하지만 단점에 비해 장점이 명확하다.
장점
수 많은 동시 커넥션을 빠르게 처리하는데 프로세스를 적게 만들다 보니 가볍기까지 했다.
그리고 프로세스를 적게만드는 이 구조는 엔진엑스의 설정을 동적으로 바꾸는 것을 가능하게 해요
개발자가 설정파일을 변경하고 엔진엑스에 해당 설정을 적용하면 마스터 프로세스는 그 설정에 맞는 워커 프로세스를 따로 생성해요
그리고 기존에 있던 워크 프로세스가 더 이상 커넥션을 형성하지 않도록 하죠 시간이 지나 기존 워크 프로세스가 담당하던 이벤트처리가 모두 끝나면 해당 프로세스를 종료합니다 그런데 이런 동적 설정 변경을 언제 사용할까요?
아주 대표적인 경우로 엔진엑스가 여러 동시 커넥션을 관리하는 도중에 뒷단에 서버가 추가되는 경우가 있어요 그땐 엔진엑스가 로드밸런서의 역할을 담당하게 되는 건데요 로드벨런서는 요청을 여러 서버로 분산하는 작업을 수행하죠
🤔 많은 트래픽을 어떻게 대처할까?
크게 두가지로 나타낼 수 있다.
- Scale up: 기존 서버의 성능을 높인다 (비용도 같이 올라간다)
- Scale out: 여러 대의 서버를 두어 트래픽을 분산시킨다.(물리적 or 논리적)
여기서 필자는 비용적인 부분을 생각해 논리적인 Scale out 방식을 생각했다.- 🔮 Scale out을 하기 위해서 무조건 해야 하는 일이 로드밸런싱이다!
엔진엑스뒤에 새로운 서버를 추가해야하는데 엔진엑스는 수 많은 동시 커넥션을 담당하고 있다면 설정을 바꾸기 위해 엔진엑스를 종료하기가 어려워요
그런데 동적으로 설정을 변경할 수 있다면 어떨까요? 동시 커넥션을 유지한채 그리고 기존 요청을 계속 처리하면서 뒷단에 서버를 추가할수 있겠죠
엔진엑스는 이런 설정 변경을 초당 수십번을 해도 무리없이 커넥션을 관리하고 요청을 서버에 전달해요
이벤트기반 구조라서 가능한 방식이죠
그런데 신기하게도 엔진엑스가 처음 출시되었을때는 사용자가 그리 많지 않았어요
2007년때까지만해도 아파치 서버는 여전히 웹서버 1위 자리를 차지하고 있었고 엔진엑스는 순위권에도 없었죠
2008년에는 스마트폰이 인터넷 환경을 바꾸기 시작했어요 스마트폰은 사람들이 인터넷을 더 많이 사용하게 된 계기이기도 하지만 동시 커넥션을 더 많이 생성하는 계기 이기도 했거든요
그리고 웹에 담기는 콘텐츠가 다양해지고 그 용량이 커지면서 결국 동시 커넥션 문제를 처리해야할 서버가 날이 갈수록 많아졌죠
아파치 진영도 시대에 맞게 MPM(Multi Processing Module)이라는 모듈을 추가해서 성능을 개선해요 MPM이란 아파치 서버를 어떤 방식으로 운영할지 선택하게 할 수 있게끔 해주는 모듈이였어요 안정성이나 하위호환이 필요하다면 기존의 prefork방식을 사용하고 성능향상을 원한다면 워커라고 불리는 스레드를 만들어서 워커가 요청을 처리하도록 했죠 개발자들은 이렇게 구조적인 한계를 그나마 줄이기 위한 시도를 계속해서 해요
그런데 성능테스트 결과를 보면 아직까지 동시 커넥션관련 지표에서는 엔진엑스가 아파치를 크게 앞서요
이 지표는 동시 커넥션 수당 메모리 사용률인데요 엔진엑스는 동시 커넥션이 많아져도 메모리 사용률이 낮고 일정하게 나오는 반면 아파치 서버는 굉장히 많이 사용하죠
동시커넥션 수가 많아 졌을 때 처리하는 초당 요청수는 오히려 엔진엑스가 훨씬 많고 아파치는 낮다는 것을 볼 수 있어요 최소 두배 이상 차이나는 것을 볼 수 있죠 이는 엔진엑스가 커넥션 관리를 얼마나 잘하고 있는지 보여줘요
사실 저희가 동시커넥션 이라는 포인트에만 집중해서 그렇지 아파치가 아직 엔진엑스와 1, 2위를 다투는데에는 다 그만한 이유가 있어요
아파치 서버는 서버 자체가 다양한 OS에서 안정적이라는 장점이 있어요 엔진엑스는 그렇지 않아서 윈도우에서 제대로 된 성능을 발휘하지 못하죠
그리고 모듈을 추가해서 그 기능을 확장하기 쉽다는 장점 기억하시나요 아파치 서버로 만들어진 오래된 서비스라고 해도 현재 잘 돌아가고 있고 모듈로 기능을 계속 추가할 수 있다면 굳이 다른 서버로 옮길 필요는 없겠죠 그리고 모듈의 종류는 아파치 서버가 엔진엑스보다 훨씬 많아요
각 웹서버가 어떤 이유로 나왔는지 알면 그 서버를 왜 선택해야 하는지 알 수 있다는 것을 말하고 싶었어요 이 두서버가 탄생한 계기를 보면 대립관계가 아니거든요 애초에 만들어진 목적 자체가 달랐던거죠 아파치 서버가 세계 1등을 할때는 안정성과 확장성이 무엇보다 중요했고 엔진엑스가 치고 올라올때는 동시 커넥션 문제가 너무나도 중요한 상황이였어요
과연 우리는 엔진엑스를 어떻게 사용해야 하는가
앞서 저희는 엔진엑스의 웹 서버로서의 기능 그리고 로드밸런서로서의 기능을 살펴 봤어요 그런데 엔진엑스는 동시 커넥션을 여러개 유지 할 수있고 그 자체가 가볍다는 장점을 살려서 이 외에도 다양한 방법으로 웹서버 가속기 역할을 해요
먼저 엔진엑스는 SSL터미네이션 역할을 수행할 수 있어요 SSL터미네이션이란 엔진엑스가 클라이언트와는 https통신을 하고, 서버와는 http 통신을 하는것을 말해요
이 구조를 만들어서 서버가 복호화하는 과정을 감당하지 않도록 할 수 있어요 비즈니스 로직처리에 리소스를 사용할 수 있도록 부하를 줄여줘요 보통 엔진엑스와 서버는 같은 네트워크안에서 있는 경우가 많기 때문에 이 둘은 http통신을 해도 보안적인 위험이 비교적 적어요
두번째로 엔진엑스 http프로토콜을 사용해서 전달하는 콘텐츠를 캐싱할 수 있어요 앞서 SSL터미네이션을 설명할때는 서버와 엔진엑스가 같은 네트워크에 있다고 말했는데 캐싱을 하는 경우에는 엔진엑스를 반대로 클라이언트에 가깝게 배치를 해요 그리고 한번 서버로 부터 받은 응답을 스스로 보관하고 클라이언트에게 전달하죠
엔진엑스는 이외에도 정말 많은 방식으로 서버를 지원해요 그러니 엔진엑스 아키텍쳐를 도입한다면 어떤 기능이 있는지 알아보고 적극적으로 적용해보면 좋을것 같다.
트래픽이 많은 웹사이트의 서버(WAS)를 도와주는 비동기 이벤트 기반구조의 웹 서버 프로그램이다.
장점
단점
장점, 특징
Event-Driven Model(이벤트 기반 구조)
단점
event-driven의 비동기 구조
reverse proxy
load balancing
무중단 배포
https://shutcoding.tistory.com/68
https://gmlwjd9405.github.io/2018/10/27/webserver-vs-was.html
https://www.youtube.com/watch?v=6FAwAXXj5N0
https://velog.io/@davidko/Nginx%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0
https://github.com/h5bp/server-configs-nginx