Nginx에 대해 알아보자

라모스·2023년 5월 16일
0
post-thumbnail

프로젝트에서 Nginx나 Public Cloud에서 제공해주는 Load Balancer 제품을 간단하게 사용만 해봤지 제대로 알고있는지에 대해 자문하다보니 아는게 없어서 정리해보고자 한다.

이번 포스팅에선 Nginx에 대한 개념부터 짚어보자.
(추 후 실 서버에서 Nginx를 구성한 뒤 스크린샷 첨부 예정)

Nginx?

Nginx란 트래픽이 많은 웹 사이트의 서버(WAS)를 도와주는 비동기 이벤트 기반 구조의 경량화 웹 서버 프로그램이다.

  • 클라이언트로부터 요청을 받았을 때 요청에 맞는 정적 파일을 응답해주는 HTTP Web Server로 활용
  • WAS의 부하를 줄일 수 있는 로드밸런서의 역할을 위해 Reverse Proxy Server로 활용

정적 콘텐츠 제공

먼저, Nginx 및 모듈이 작동하는 방식은 구성 파일에서 정의된다. 기본적으로 구성 파일 이름은 nginx.conf로 지정되고, /usr/local/nginx/conf, /etc/nginx 또는 /usr/local/etc/nginx 디렉터리에 저장된다.

conf 파일의 내부를 보며 어떻게 구성하는지 간단하게 알아보자.

중요한 웹 서버 작업은 파일(예: 이미지,정적 HTML 페이지)을 서비스한다. 요청에 따라 각 로컬 디렉터리에서 파일을 서비스하는 /data/www(HTML 파일 포함)/data/images(이미지 포함)의 예시를 구현해보자. 구성 파일을 편집하고, http 블록 내의 server 블록을 두 개의 location 블록으로 설정해야 한다.

먼저 /data/www 디렉터리를 만들고 index.html 파일에 아무 텍스트를 넣은 다음, /data/images 디렉터리를 만들어 몇 개의 이미지를 넣는다.

그런 다음 구성 파일을 연다. 기본 구성 파일에는 이미 server 블록의 여러 예시가 포함되어 있으며, 대부분은 주석 처리되어 있다. 이제 모든 해당 블록을 주석처리하고 새 server 블록을 시작한다.

http {
	server {
        location / {
             root /data/www;
        }

        location /images/ {
             root /data;
        }
    }
}

위 예제는 표준 포트 80을 수신하는 서버에서 이미 작동하는 구성이며, http://localhost/에서 로컬 PC에 액세스할 수 있다.

  • /images/로 시작하는 URI를 포함하는 요청을 받으면 서버는 /data/images 디렉터리에서 파일을 전송한다.
    • 예를 들어 nginx는 http://localhost/images/example.png 요청에 응답하여 /data/images/example.png 파일을 전송한다.
    • 이러한 파일이 존재하지 않을 경우, nginx가 404 오류를 나타내는 응답을 보낸다.
  • /images/로 시작하지 않는 URI를 포함한 요청은 /data/www 디렉터리에 매핑된다.
    • 예를 들어 nginx는 http://localhost/some/example.html 요청에 응답하여 /data/www/some/example.html 파일을 전송한다.

로드밸런서와 Reverse Proxy

프록시(Proxy)?

Proxy Pattern, Proxy Server 등 다양한 용어가 많은데 여기서 말하는 프록시의 사전적 의미는 '대리', '대신'이다. 보안상의 문제로 직접 통신을 주고받을 수 없는 두 PC 사이에서 통신을 할 때 직접하지 않고 중간에서 대리로 중계를 하는 개념을 프록시라 한다.

이렇게 중계 기능을 하는 것을 프록시 서버라고 한다.

프록시 서버는 서버가 어디에 위치하느냐에 따라 Forward Proxy와 Reverse Proxy로 나뉜다. 각각의 경우 용도와 역할도 다르다.

Forward Proxy

앞서, 클라이언트에서 서버로 리소스를 요청할 때 직접 요청하지 않고 프록시 서버를 거쳐서 요청한다고 했다.

서버에서 받는 IP는 클라이언트의 IP가 아닌 프록시 서버의 IP기 때문에 서버는 클라이언트가 누군지 알 수 없다. 따라서 서버에게 클라이언트가 누구인지 감춰주는 역할을 한다.

Forward Proxy는 캐싱 기능이 있으므로 자주 사용되는 컨텐츠라면 월등한 성능 향상을 가져올 수 있으며 정해진 사이트만 연결하게 설정하는 등 웹 사용 환경을 제한할 수 있으므로 보안이 중요한 환경에서 많이 사용된다.

Reverse Proxy

Reverse Proxy는 Forward Proxy와 반대 개념이다. 애플리케이션 서버의 앞에 위치하여 클라이언트가 서버를 요청할 때 Reverse Proxy를 호출하고 이 프록시가 서버로부터 응답을 전달받아 다시 클라이언트에게 전송하는 역할을 한다.

클라이언트는 애플리케이션 서버를 직접 호출하는 것이 아니라 서버를 통해 호출하기 때문에 Reverse Proxy는 애플리케이션 서버를 감춰주는 역할을 한다.

단순 프록시 서버 설정

로컬 디렉터리에 있는 파일을 포함한 이미지에 대한 요청을 서비스하고, 그 외에 다른 요청은 프록시된 서버로 전송한다. 이 예제에서는 두 서버를 하나의 nginx 인스턴스에서 정의할 것이다.

먼저 server 블록을 하나 더 nginx 구성 파일에 추가하여 다음과 같은 내용으로 프록시된 서버를 정의한다.

http {
    server {
        location / {
            proxy_pass http://localhost:8080/;
        }

        location ~ \.(gif/jpg/png)$ {
            root /data/images;
        }
    }
}

이 서버는 .gif, .jpg 또는 .png로 끝나는 요청을 필터링하고 (URI를 root 명령의 매개변수에 추가하여) /data/images 디렉터리에 매핑한다. 그 외에 다른 요청은 위에서 구성한 프록시된 서버로 보낸다.

Nginx가 만들어진 배경

httpd

1995년, UNIX 기반의 NCSA httpd가 나왔다. 이 프로그램은 버그가 굉장히 많아 개발자들이 사용할 때 불편함이 많았다.

Apache Server

httpd의 문제를 해결하기 위해 탄생한 것이 Apache Server이다.

요청이 들어오면 connection을 생성하는 방식이다. 새로운 클라이언트의 요청이 올 때마다 새로운 process를 생성하게 된다.

프로세스를 생성하는 과정은 3-Way-Handshake에 따라 시간이 오래걸린다. 이 때문에 프로세스를 미리 만들어두는 PREFORK라는 방식을 이용하게 된다. 새로운 클라이언트의 요청이 오면 미리 만들어 둔 프로세스를 할당시키고, 만들어둔 프로세스가 없다면 추가로 프로세스를 생성한다.

이런 구조 덕에 개발자는 다양한 모듈을 만들어 서버에 빠르게 기능을 추가할 수 있었다. 즉, 확장성이 높고 동적 컨텐츠를 처리할 수 있게 되었다. 이는 요청을 받고 응답을 처리하는 과정을 하나의 서버에서 해결하기 좋은 구조이다.

1999년에 들어 컴퓨터의 보급률이 높아지자 요청 또한 많아져서 서버에 동시에 연결된 connection 수가 자연스럽게 늘게 되었다. C10K(connection 10000 problem) 문제가 발생하는 한계가 생겨났다.

  • 메모리 부족: connection이 연결될 때마다 프로세스 생성
  • Apache Server의 무거운 프로그램 구조: 확장성이 좋다는 것은 곧 리소스가 많다
  • CPU 부하 증가: 많은 connection 요청이 들어오면 context switching을 많이 하기에 CPU 부하가증가

Nginx

즉, Apache Server는 현대로 올수록 사용하기 꺼려졌고, 이러한 구조적 문제점을 해결한 Nginx가 2004년에 나왔다.

초창기 Nginx는 Apache와 함께 사용하기 위해 만들어졌다. 웹 서버이기는 하지만 아파치 서버를 완전히 대체할 목적은 아니었다. 아파치 서버가 지닌 구조적 한계를 Nginx를 사용하면서 극복하려고 했다.

위 그림과 같이 수많은 동시 connection을 Nginx가 유지하고, Nginx도 웹 서버이기 때문에 정적 파일에 대한 요청은 스스로 처리하고, 클라이언트로부터 동적 파일의 요청을 받았을 때만 아파치 서버의 connection을 형성하여 아파치 서버의 부하를 줄이게 된다.

Nginx의 구조

Nginx가 많은 동시 connection 유지를 할 수 있는 그 기반은 무엇일까?

  • Nginx는 설정 파일을 읽고, 설정에 맞게 worker process를 생성하는 master process가 있다.
  • worker process는 실제로 일을 하는 프로세스이고 이 프로세스가 만들어질 때 지정된 listen 소켓을 배정받는다.
  • 해당 소켓에 새로운 클라이언트의 요청이 들어오면 connection을 형성하고 처리한다.
  • connection은 정해진 Keep-Alive 시간만큼 유지된다. 그러나 connection이 형성되었다고 worker process가 해당 connection 하나만 담당하진 않는다.
  • connection으로부터 아무런 요청이 없다면 새로운 connection을 형성하거나 이미 만들어진 다른 connection으로부터 들어온 요청을 처리한다.

Nginx에서의 이러한 connection 형성과 제거, 새로운 요청을 처리하는 일을 이벤트(event)라고 한다.

이 이벤트들은 OS Kernel이 queue 형식으로 worker process에게 전달한다. 해당 이벤트들은 큐에 담긴 상태에서 비동기 상태로 대기한다. worker process는 하나의 스레드로 이벤트를 꺼내서 처리해간다.

이런 방식은 worker process가 쉬지 않고 일을 하기에, 요청이 없을 때 유휴 상태의 프로세스를 두는 Apache Server보다 훨씬 효율적으로 자원을 사용할 수 있다.

Nginx의 장단점

Nginx의 단점

  • 동적 컨텐츠를 기본적으로 처리 할 수 없다.
  • 동적 콘텐츠에 대한 요청을 처리하려면 Nginx를 실행하기 위해 외부 프로세서로 전달하고 렌더링 된 콘텐츠가 다시 전송 될 때까지 기다려야 한다(프로세스 속도 저하).
  • 즉, 동적 웹 페이지 컨텐츠를 가진 모든 요청을 위해 외부 자원과 연계한다.(ex. php-fpm)

Nginx의 장점

  • 이벤트 중심 접근 방식을 사용하여 클라이언트 요청 제공
  • 제한된 하드웨어 리소스로도 여러 클라이언트 요청을 동시에 효율적으로 처리
  • 단일 스레드를 통해 여러 연결을 처리 가능
  • 최소한의 리소스로 웹 서버의 아키텍처를 개선하기 위해 독립형 HTTP 서버로 배치 가능

Apache vs Nginx

동시 connection 수 당 메모리 사용률을 나타내는 그래프이다. Nginx는 Apache에 비해 커넥션 수가 늘어나도 메모리 사용률이 낮고 일정하다.

동시 connection 수가 많아졌을 때 처리하는 초당 요청 수는 Nginx가 Apache에 비해 압도적으로 높다는 것을 나타낸 그래프이다.

Apache의 한계

Apache는 클라이언트 접속마다 Process 혹은 Thread를 생성하는 구조이다. 10,000 클라이언트로부터 동시 접속 요청이 들어온다면 CPU와 메모리 사용률이 증가하고 추가적인 Process 생성 비용이 드는 등 대용량 요청에서 한계가 나타난다.

Apache 서버의 프로세스가 blocking 될 때 요청을 처리하지 못하고 처리가 완료될 때까지 대기상태로 남는다. 이는 Keep Aliver로 해결이 가능하나 효율이 좋지 않다.

Nginx는 Event Driven 방식으로 동작하기에 한 개 또는 고정된 프로세스만 생성하고, 그 내부에서 비동기로 효율적인 방식으로 task를 처리한다. Apache와 달리 동시 접속자 수가 많아져도 추가적인 생성 비용이 들지 않는다.

CPU 소모가 적고 CPU와 관계 없이 I/O를 전부 이벤트 리스너로 미루기 때문에 흐름이 끊기지 않는다. 또한 context switching 비용이 적다.

References

profile
Step by step goes a long way.

0개의 댓글