장바구니 웹 협업 미션에서 배포시 Nginx를 활용했는데, Nginx란 무엇인지 알아보도록 하자.
참고로, Nginx를 이해하기 위해서는 웹서버와 WAS, 그리고 Reverse Proxy 개념에 대해서 숙지하고 있어야한다.
해당 개념들은 아래 포스팅에서 정리했으니 참고하도록 하자.
Nginx란?
NGINX는 고성능, 확장성, 고가용성 웹서버, 역방향 프록시 서버 및 웹 가속기(HTTP 로드밸런서, 콘텐츠 캐시 등의 기능 결합)이다. (출처: 공식문서)
Nginx란 트래픽이 많은 WAS를 도와주는 비동기 이벤트 기반구조의 경량화 웹 서버 프로그램이다.
한마디로 말해, 경량 웹 서버이다.
클라이언트로부터 요청을 받아 정적 컨텐츠를 제공하는 HTTP Web Server로 활용되기도 하고,
WAS 서버 부하를 줄이는 로드밸런서 역할을 하는 Reverse Proxy Server로 활용되기도 한다.
Apache 서버와의 차이점
웹 서버 2대장으로 Apache HTTP Server 와 Nginx를 언급한다.
Nginx는 아파치 서버에서 대규모 연결 처리 문제를 해결하기 위해 등장했다고 한다.
여기서 아파치 서버와 Nginx의 차이점은 무엇일까?
아파치 - 멀티 프로세스
아파치는 멀티 프로세스 아키텍처를 사용한다.
즉, 각 클라이언트 요청은 별도의 프로세스 또는 스레드에서 처리된다.
이는 요청마다 새로운 프로세스 또는 스레드를 생성하기 때문에 그만큼 CPU와 메모리 자원의 소모가 높아질 수 있다.
단점만 존재하는가?
아니다. 이 구조는 동적인 컨텐츠를 처리하는데 적합하다는 장점을 가진다.
각 요청은 독립적인 프로세스에서 처리되므로, 한 요청의 처리가 지연되더라도 다른 요청에는 영향을 주지 않기 때문이다.
또한, 아파치 서버는 모듈 기반 아키텍처를 가지고 있어서 다양한 모듈과 플러그인을 지원한다.
이는 확장성면에서 큰 장점을 가진다.
다양한 운영 체제와 플랫폼에 동작할수 있어 호환성이 뛰어나며 다양한 환경에서 적용할 수 있다는 장점도 있다.
Nginx - 이벤트 기반
Nginx는 이벤트 기반 아키텍처를 사용한다.
즉, 한 개 또는 고정된 스레드/프로세스에서 여러 클라이언트 요청을 비동기 방식으로 동시에 처리한다.
Nginx는 새로운 요청이 들어와도 새로운 프로세스 및 스레드를 생성하지 않기 때문에, 프로세스/스레드 생성 비용이 존재하지 않고, 적은 자원으로도 효율적인 운용이 가능하다.
이러한 특징 덕분에, Nginx에서는 동시에 많은 연결을 처리할 수 있다.
Nginx 구조
다수의 동시 connection을 유지 가능하도록한 Nginx의 구조에 대해 알아보자.
위 그림과 같이 Nginx는 하나의 마스터 프로세스(Master Process)와 다수의 워커 프로세스(Worker Process)로 구성되어 실행된다.
마스터 프로세스
마스터 프로세스(Master Process)는 설정 파일을 읽어 설정에 맞게 워커 프로세스를 생성한다.
이외에도, Nginx 서버를 시작하고 중지하며, 네트워크 연결을 관리하고, 신호를 처리하며, 워커 프로세스간의 통신을 담당하는 역할도 한다.
워커 프로세스
워커 프로세스(Worker Process)는 실제로 요청을 처리하는 역할을 한다.
설정 파일에 워커 프로세스 개수를 정의할 수 있다. (기본적으로는 CPU 코어 당 하나의 워커 프로세스를 실행한다.)
각 워커 프로세스는 단일 스레드를 사용하여 독립적으로 클라이언트 요청을 처리한다.
이 때, 위 사진처럼 비동기 방식으로 여러 커넥션을 관리함으로써 컨텍스트 스위칭 횟수를 줄인다.
(CPU 코어수 만큼 프로세스를 생성하고, 하나의 프로세스 내에서 비동기 방식으로 커넥션을 관리하므로 각 코어가 담당하는 프로세스를 바꾸는 횟수를 줄일 수 있다. → CPU 컨텍스트 스위칭 횟수를 줄인다.)
프로세스들은 공유 메모리를 사용하여 공유 캐시 데이터, 세션 지속성 데이터 및 기타 공유 리소스를 공유한다.
워커 프로세스 동작 방식
워커 프로세스가 만들어질 때 마스터 프로세스로부터 지정된 listen 소켓을 배정받는다.
이 때, 워커 프로세스는 listen 소켓에서 발생하는 이벤트를 대기하는 상태가 된다.
해당 소켓에 새로운 클라이언트의 요청이 들어오면 커넥션을 형성하고 처리한다.
이 때, 커넥션은 정해진 Keep-Alive 시간만큼 유지된다.
(커넥션이 형성되었다고 해서, 워커 프로세스가 해당 커넥션 하나만 담당하지는 않는다. 위에서도 언급했듯, 워커 프로세스는 비동기 방식으로 여러 커넥션을 관리한다.)
형성된 커넥션으로부터 아무런 요청이 없으면, 새로운 커넥션을 형성하거나 이미 만들어진 다른 커넥션으로부터 들어온 요청을 처리한다. 즉, 서버 자원을 효율적으로 사용한다.
(아파치 서버에선 커넥션 연결 후 요청이 없으면 방치된다.)
이 때 연결 요청들은 일반적으로 요청 큐에 저장되고, 워커 프로세스는 순서대로 큐에서 요청을 가져와 처리한다.
스레드풀
Nginx는 여러 이벤트를 큐 형태으로 수신하고, 이를 하나씩 처리하며 필요한 작업을 수행한다.
이 때, 하나의 의문이 생긴다.
만약 한 요청에서 긴 시간이 걸린다면?
대부분의 이벤트 처리는 매우 빠르게 수행되므로 별 문제가 없을 수 있다.
하지만, 동기 방식으로 DB에서 응답을 받거나 뮤텍스 또는 라이브러리 함수를 호출하는 요청을 수행하는데는 긴 시간이 소요된다.
위 요청을 처리하는 동안, 워커 프로세스는 다른 작업을 수행할 수 없으므로 이벤트를 처리할 수 없어 성능이 매우 저하된다.
이를 위해서 Nginx는 스레드풀(Thread Pool) 개념을 도입했다.
워커 프로세스에서는 처리할 요청이 시간이 오래 걸릴 것 같으면, 스레드 풀에 이벤트를 위임하고 다른 이벤트를 처리한다.
즉, 워커 프로세스가 요청을 TASK_QUEUE에 넣으면, 해당 요청을 스레드풀에 있는 스레드들이 수행한 후 수행 결과를 다시 워커 프로세스에게 전달한다.
Reverse Proxy
Nginx는 리버스 프록시로도 활용할 수 있다.
리버스 프록시는 쉽게 말해 클라이언트와 서버 사이 요청의 중개자 역할을 하는 서버이다.
리버스 프록시에 대한 자세한 설명은 해당 포스팅 을 참고하도록 하자.
Nginx를 리버스 프록시로 활용함으로써 다음과 같은 이점을 얻을 수 있다.
보안
외부 사용자로부터 내부 망에 있는 서버의 존재를 숨길 수 있다.
모든 요청은 리버스 프록시 서버에서 받으며, 매핑되는 내부 서버로 요청을 가능하다.
Nginx는 ssl 설정도 가능하다. (클라이언트와 https로 통신하고, 서버와는 http통신할 수 있다.)
로드 밸런싱
Nginx가 로드밸런서로서 요청을 여러 서버로 분산하는 작업을 수행한다.
즉, 각 서버의 상태에 따라 부하를 분산시키며 요청을 전달할 수 있다.
동적 설정 변경
Nginx는 프로세스를 적게 생성하기 때문에, Nginx의 설정을 동적으로 바꿀 수 있다.
해당 과정을 간략하게 살펴보자.
- 설정 파일을 변경하면, 마스터 프로세스는 새로운 워커 프로세스를 만들어 요청을 처리한다.
- 이전 워커 프로세스는 더이상 새로운 커넥션을 생성하지 않는다. 현재 처리중인 요청을 모두 처리하면, 해당 워커 프로레스를 종료시킨다.
동적 설정 변경은 Nginx의 유연성과 확장성을 높이는 중요한 기능 중 하나이며, 서버의 구성을 런타임 중에도 쉽게 조정할 수 있는 장점을 제공한다.
해당 동적 설정 변경은 언제 사용될까?
Nginx가 로드밸런서 역할을 담당 하는 경우를 가정하자.
이 때, 뒷단에 서버를 한 대 더 추가한다고 가정하자.
동적 설정 변경을 사용하면 기존의 커넥션을 유지하며 새로운 서버를 한 대 더 추가할 수 있다.
참고 자료
'프로그래밍 > 인프라' 카테고리의 다른 글
[Proxy] Forward Proxy와 Reverse Proxy (0) | 2023.05.28 |
---|---|
웹 서버와 WAS (0) | 2023.05.25 |