C언어로 만들어진 고성능 네트워크 서버다.
이벤트 루프 기반 구조
Nginx는 이벤트 루프 기반으로 요청을 처리하기에 적은 스레드로 많은 양의 요청을 처리할 수 있다.
Apache 서버나 Spring 서버의 경우 요청에 따라 각각의 스레드가 전담을 하게 되고,
Spring의 경우에는 해당 요청이 마무리 될때까지 스레드가 블로킹되기도 한다.
이러한 스레드풀 구조는 하나의 요청에 대해서 스레드가 루프되지 않고 전담하기에 복잡한 비즈니스 로직에서는 더 빠를 수 있으나, 요청이 많아져 스레드에 비해 요청이 많아진다면 스레드가 블로킹되어 속도가 많이 느려진다.
반대로 이벤트 루프 기반 구조는 스레드가 하나의 요청을 전담하지 않고, 발생하는 요청들을 순회하며 처리 가능한 요청들부터 처리하기에, 스레드가 블로킹 되지 않는다.
때문에 NginX는 이벤트 루프 기반으로 작동하고,
클라이언트의 요청을 Nginx가 먼저 받은 뒤 메인 서버(Spring, Node.js 등)으로 전달하는 방식이다.
Client -> Nginx -> Server
메인 서버를 숨김으로서 보안성에 유리하고, 구조를 분리하여 클라이언트와 메인 서버의 결합을 낮출 수 있다.
이렇게 Nginx를 리버스 프록시로 두게 한다면 여러가지 방법으로 응용이 가능하다.
Client <--> HTTPS <--> Nginx
Nginx <--> HTTP <--> 서버
HTTPS 인증을 클라이언트와 Nginx만 하게 두어,
Nginx의 Keep-alive, timeout 설정등을 통해 클라이언트와 연결을 관리할 수 있다.
특히 slow client 연결이나 대량 동시 연결을 nginx가 우선 처리함으로써, backend 서버의 부담을 줄일 수 있다.
프록시 설정
etc/nginx/nginx.conf
...
location / {
proxy_pass http://localhost:8080;
}
...
백엔드 서버가 여러개일 경우 Nginx를 통해 서버 그룹을 정의하는 개념으로
로드 밸런서와 같이 사용된다.
upstream backend {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
server {
location / {
proxy_pass http://backend;
}
}
Nginx를 통해 서버를 분산시킬 수 있다.
이러한 로드를 분산시키는 알고리즘도 직접 정할 수 있다.
upstream backend {
least_conn;
server app1;
server app2;
}
---
upstream backend {
ip_hash;
server app1;
server app2;
}
---
upstream backend {
server app1 weight=3;
server app2 weight=1;
#app1에 더 많은 요청을 분산
}
least_conn : 연결이 적은 서버 우선 분산
ip_hash : 같은 클라이언트는 같은 서버로 연결
weight : 서버 성능 차등 분산
아무것도 적지 않는다면 순차적으로 분산시킨다.
HTTPS를 nginx가 담당하는 방법이다.
위에서 언급했듯 클라이언트와 Nginx만 서로 HTTPS 통신을 주고 받고 메인 서버는 Nginx와 HTTP통신을 주고받아 메인 서버의 부하를 줄이고, 인증서 관리를 중앙화 할 수 있다.
인증서관련 설정 : Nginx 공식 문서
이 외에도
실제 사용 예시
프로젝트에서 무중단 배포를 구현하기 위해 Docker에서 8080, 8081포트에서 실행중인 두 메인 서버를 Nginx를 통해 Upstream해 사용했다.
클라이언트 -> AWS HTTPS -> (EC2 -> Nginx -> Docker(8080, 8081))