'엔진 엑스' 로 발음되는 NGINX 는 널리 사용되는 오픈 소스 웹 서버 소프트웨어이다. 2002년 Igor Sysoev가 시작한 프로젝트였으며 2004년 10월에 공식적으로 출시되었다. 동시에 10,000개의 연결을 관리해야 하는 과제로 정의되는 C10k의 문제를 해결하기 위해 만들어졌다.
Apache 서버
아파치 서버는 1995년에 나왔으며 nginx는 2002년에 출시됐다 왜 nginx를 사용하는지 왜 1등이되었는지 를 알기위해서는 아파치 서버가 만들어진 1995년부터 내려가보자 그당시에는 유닉스 기반으로 만들어진 최초의 웹서버 NCSA HTTPd 가 있었다 하지만 이 웹서버는 버그가 굉장히 많아서 개발자들이 수정하면서 변경하고 기능도 추가해서 만든게 아파치 서버다.
아파치 서버는 요청이 들어오면 아파치는 unix계열의 OS가 네트워크 커넥션을 생성하는 방식과 유사하게, 유저 요청이 들어오면 하나의 프로세스를 할당해 처리하게 구현했다. 프로세스를 생성하는 비용은 부하가 상당하기 때문에, 프로세스를 미리 생성해서 할당하는 PREFORK 방식을 활용했다.
유저 하나가 접근하면 PREFORK 과정을 통해 생성해놓은 프로세스 하나를 할당해 유저의 HTTP 요청을 처리한다. 만약 PREFORK로 만들어놓은 프로세스가 이미 누군가의 요청을 처리하고 있다면 새로운 Process를 만들어 처리한다.
유저 요청 하나에 대해 프로세스 하나를 할당하는 이 방식을 Process Driven이라고 부르기도 하는데
이 방식은 다양한 모듈을 만들어 유저 요청을 동적으로 처리하기 좋았습니다. 요청을 받아 응답을 내보낸다 라는 로직 중간에 모듈로서 필요한 로직을 구현해두면 아파치가 해당 로직을 포함한 프로세스를 만들어 유저 요청을 처리하게된다.
출시된 지 1년도 되지 않아 아파치는 기존 웹서버들을 밀어내고 업계 1위의 자리에 올라사게된다.
C10K 문제
시간이 흘러 1999년, PC의 보급률이 높아지기 시작한다. 그리고 인터넷이 세간에 널리 보급되기 시작했다. 승승장구 하던 Apache는 새로운 도전에 직면하게 되는데 이전과 다르게 많아진 트래픽, 즉 클라이언트로부터의 커넥션을 처리할 프로세스를 새롭게 생성해주지 못하는 문제가 생기게된다. 이 문제를 두고 커넥션 10,000개 문제, 줄여서 C10K 문제라고 불렸다.
CPU 성능 문제일까? 당시 하드웨어는 1만개의 요청 정도는 처리할 수 있을 정도로 발전해있었다. 문제는 apache의 내부 구조 때문이었다. apache의 장점이었던 모듈을 쉽게 얹을 수 있었던 점으로 인해 서버 프로세스가 무거워 지고, 무거운 프로세스를 유저 connetion 수만큼 생성하니 메모리가 버티지 못한 것이었다. 또 수많은 프로세스가 끊임없이 CPU를 컨텍스트 스위칭 하는 비용도 상당했다. 여러모로 다중 요청을 처리하기엔 부적합한 구조이다.
먼저 짚고나가자면
동시에 연결된 커넥션 수와 초당 요청 처리수와는 다르다 초당 요청 처리 수는 말그대로 서버가 얼마나 빨리 많은 요청을 처리하는걸 말하고
동시에 연결된 커넥션 수는 요청을 처리하기위해 서버가 한 시점에 얼마나 많은 클라이언트와 커넥션을 형성하는지 나타낸다.
한 클라이언트는 하나의 커넥션으로 요청을 보낼 수 있는고 커넥션은 긴 시간동안 유지될 수도 있는데 이둘은 그렇기 때문에 같다고 볼 수 없다.
커넥션이 길게 유지되는 이유는 그 커넥션을 유지하는데 많은 절차들이 있기 때문이다 그래서 그 당시에는 각 요청마다 커넥션을 생성하는게 비효율적이라고 생각이들어서 사람들은 요청할때 이미 만들어진 커넥션이 있다면 재사용 하자는 생각을 하게된다. HTTP프로토콜을 보면 헤더중에 Keep-Alive가있는데 이헤더에 적힌 시간 만큼 클라이언트와 서버는 형성된 커넥션을 유지한다. 하지만 클라이언트 수가 많아지면 동시에 연결된 커넥션 수가 많이 늘어나는데 이렇게 커넥션 수 가 만 단위를 넘어가는 순간 서버는 더이상 커넥션을 형성하지못하는 상황에 이른다 드디어 NGINX
NGINX
2004년 드디어 새로운 구조를 채택하면서 아파치 서버를 보완하기위해 NGINX가 나오게된다. 엔진엑스는 아파치 앞단에 두어 아파치가 받을 커넥션을 줄여줄 목적으로 만들어졌다. 어떻게 커넥션을 줄이는걸까 엔진엑스는 그 자체로 웹서버이기 때문에, HTML, CSS, JS, 이미지 등의 정적파일은 직접 반환할 수 있다. 그리고 동적으로 처리해줘야할 요청만 apache로 보냄으로써 connection을 줄일 수 있습니다. 해당 요청은 nginx에는 keep-alive설정으로 여전히 연결되어있지만 apache로 보낼 때에는 별도 요청으로 받아옴으로써 해당 커넥션을 유지시키지 않을 수 있다.

nginx도 다중 커넥션이 연결되어 있는데 아파치처럼 프로세스 문제가없을까 생각이들겠다. nginx는 해결 방법으로
마스터 프로세스, 워커 프로세스
해결방법으론 요청이 많이 들어와도 프로세스를 늘리지 않는다 이다
엔진엑스는 설정파일을 읽고 워커 프로세스를 생성하는 역할을 하는 마스터 프로세스와, 실제로 유저 요청을 처리하는 워커 프로세스로 이루어져 있다. 엔진엑스가 구동되면 마스터 프로세스는 정해진 숫자만큼의 워커 프로세스를 생성하고, 리슨 소켓(워커 프로세스와 통신할 수 있는 소켓 디스크립터)을 배정하게된다
또한 워커 프로세스의 숫자가 정해져 있는데 어떻게 다중 커넥션의 요청을 동시에 처리할수 있을까 생각이 든다.
이벤트 드리븐 Event Driven
이벤트 드리븐에선 TCP(or UDP) connection의 연결, 유저의 Http Request 처리, Connection의 종료까지의 모든 절차를 이벤트 라는 개념으로 취급하고 한다. 그리고 워커 프로세스에게 working queue라는 이름의 처리해야할 작업이 순차적으로 담긴 큐를 처리하도록 합니다. 이렇게 구현하면 워커 프로세스가 놀고 있는 시간 없이 끊임없이 이벤트를 처리하게 된다. 커넥션에서 아무런 요청도 들어오지 않고 대기하고 있는 keep-alive 상황에서는 하는 일 없이 메모리만 차지하던 apache의 프로세스 와는 대조적이다.
하지만 위 방식도 완벽하진 않는데 만약 working queue의 disk I/O처럼 시간이 오래 걸리는 작업 하나가 들어온다면 어떻게 될까 해당 작업이 처리되는 동안, working queue의 작업들은 전부 대기해야 할거다.
그래서 엔진엑스는 오래 걸리는 작업(Disk 읽기, 파일 전송하기)을 처리하는 Thread Pool을 따로 만들어 놓았다.(1.7.11버전 이후)
Thread Pool은 생성비용이 비싼 스레드를 필요할 때 편하게 늘리기 위해 스레드를 미리 만들어놓고 필요한 작업에게 할당해주는 개념이다.
각 워커 프로세스들은 Disk I/O 처럼 오래 걸리는 작업이 감지되면 해당 작업만 처리하는 역할을 하는 Thread Pool에게 처리를 위임하고 다른 이벤트를 처리하는데 이 Thread Pool은 32개의 default 스레드 수와 65535 default 크기를 가진 working queue를 가지고 있고, 여러 워커 프로세스로부터의 파일 읽기 or 전송 작업을 working queue에 넣어놓고 32개의 스레드 중 놀고 있는 thread를 할당해 일을 처리한다.
보통 엔진엑스는 코어 개수만큼의 워커 프로세스를 만든다. 그리고 워커 프로세스가 하나의 코어만을 이용하도록 할당하게된다. cpu에선 프로세스를 변경하는 컨텍스트 스위칭을 거치지 않아도 되고, 그만큼 cpu 부하가 감소한다.
Nginx의 단점
하지만 위의 구조도 약점이 존재하는데 개발자가 실수로 프로세스를 종료하게 되면 해당 프로세스가 관리하고 있던 모든 커넥션이 끊기게 된다.
Nginx의 성능 향상
하지만 Nginx의 장점이 너무나 명확했다. 같은 자원을 가지고 처리할 수 있는 커넥션 양이 아파치에 비해 압도적으로 많았으니까말이다.
또한 이벤트 드리븐 구조를 통해 가질수 있는 장점은 또 하나 더 있었는데
동적인 설정변경
바로 엔진엑스 서버가 동작하고 있을 때에도 동적으로 설정을 변경할 수 있다는 점이다.
보통 서버 프로그램들은 설정을 하고 서버를 부팅하면 새로운 설정을 적용하기 위해 재부팅해야하는 경우가 많은데 엔진엑스는 이벤트 드라이븐이라는 특징 덕분에 서버가 돌고 있는 도중에도 동적으로 설정을 변경할 수 있다. 이것이 바로 Nginx를 다뤄보신 분들에겐 익숙한 키워드, service reload 이다.원리는 다음과 같은데 service reload를 하면 마스터 프로세스는 새로운 설정파일을 읽어 새롭게 워커 노드를 생성한다. 그리고 기존 워커 프로세스로는 새롭게 이벤트를 할당하지 않는다. 기존 워커 프로세스(초록색)가 모든 커넥션을 처리하고 나면, 새로운 워커 프로세스(노란색)로만 이벤트를 전달하고 기존의 워커 프로세스를 종료한다.
설치방법
리눅스 운영체제 설치방법
https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/
1. 저장소를 업데이트
$ sudo yum update #centOS
$ sudo apt update #우분투
2. nginx 오픈 소스 설치
$ sudo yum install nginx
$ sudo apt install nginx
3. 설치확인
$ sudo nginx -v
nginx version: nginx/1.6.3
4. nginx 상태를 확인하기
$ systemctl status nginx
5. curl 명령어로 확인하기
curl localhost:80
기술출처
https://www.youtube.com/watch?v=6FAwAXXj5N0
https://www.c-sharpcorner.com/article/nginx-history-overview-uses/
NGINX - History, Overview & Uses
In this article, you will learn about Nginx history, Nginx Server, Web Server , C10K Problem.
www.c-sharpcorner.com
'DevOps > Linux' 카테고리의 다른 글
[Linux] 리눅스 네트워크 네임스페이스 (1) | 2023.02.06 |
---|---|
[Linux] 리눅스 표준 스트림과 파이프라인, 리다이렉션 (1) | 2022.12.30 |
[Linux] 프록시 서버의개념, NGINX 리버스 프록시와 캐싱 (0) | 2022.12.29 |
[Linux] Read, Write, Execute 권한, chmod 권한 변경 (0) | 2022.12.02 |
[Linux] 리눅스 디렉토리 구조 개념 (0) | 2022.11.30 |