ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Nginx 탐구하기
    Tech/Backend 2020. 3. 19. 21:12

    1. Nginx

    nginx는 동시접속 처리에 특화된 웹 서버로 기존의 웹 서버보다 많은 트래픽을 감당하기 위해 설계된 비동기 Event-Driven 방식의 웹 서버이다. 이러한 목적으로, 고성능과 높은 동시처리 능력 그리고 적은 메모리 사용에 집중하고 있는 웹 서버라 할 수 있다.

     

    nginx 구조

    1-1. Event-Driven

    Thread
    Event-Driven

    말 그대로, Event-Driven은 언제 동작할지 모르는 반응(Event)가 일어났을 때 처리되는(Driven) 방식을 의미한다. 즉, 요청에 대한 각 상태를 정해서 이벤트가 발생할 때마다 이벤트를 처리하게 하는 방식이다. 이 방식을 통해서, nginx는 서버로 들어오는 요청을 이벤트로서 어떤 일을 처리해야 하는지에 대해서만 전달하고 다음 이벤트를 처리한다.

     

    그래서 하나의 프로세스를 통해서 들어오는 많은 요청들을 빠르게 처리 가능하다. 또한, CPU에 관계없이 모든 I/O들을 전부 Event-Listener로 미루기 때문에 흐름이 끊기지 않고 응답이 빠르게 진행되어 1개의 프로세스로 더 빠른 작업을 가능하게 한다. 이러한 처리 덕분에 시스템 자원을 적게 차지하게 된다는 장점이 있다.

    * 위의 Thread 방식은, 커넥션 당 하나의 Thread를 사용하기에 자원을 너무 많이 소모한다. 그러나 Event-Driven 방식을 보면 더 작은 스레드로 요청을 처리하는 것을 볼 수 있다.


    2. nginx의 역할

    2-1. HTTP 서버

    nginx는 웹 브라우저와 같은 클라이언트로부터 HTTP 요청을 받아들이고, HTML/CSS/Javascript와 같은 정적 파일들을 반환하는 HTTP 서버로서의 역할을 수행한다. nginx는 본래의 목적상 WAS보다 정적인 파일들을 서빙함에 있어서 특화되어 있고, 캐싱 기능도 갖추고 있기 때문에. 주로 Node.js와 같은 WAS 앞 단에 위치시켜 활용하고 있다. 이렇게 혼합해서 사용한다면, 처리속도 향상은 물론 백엔드의 부하도 분산시킬 수 있다는 장점을 가질 수 있다.

    2-2. Reverse Proxy

    nginx는 리버스 프록시의 역할도 수행한다. 리버스 프록시는 클라이언트의 요청을 받아서 반대편에 있는 서버로부터 데이터를 가져오는 역할을 한다. 즉, 리버스 프록시는 단순히 요청을 전달하기만 할 뿐으로 요청의 처리는 뒷 단에 있는 WAS와 같은 서버들이 맡아서 한다. 그래서, 리버스 프록시를 사용한다면, 클라이언트는 하나의 nginx 포트로만 접근하며 실제 어떤 포트에서 해당 요청을 처리하는지 모르기 때문에 보안 공격에 대한 1차적 방어선 역할도 수행할 수 있다. 

     

    또한,  하나의 리버스 프록시가 여러 웹 서버로 요청을 전달하도록 구성할 수 있기에 로드밸런싱도 가능하다.  로드밸런싱이란 트래픽 유입을 뒷 단의 서버그룹에 효율적으로 분산처리하는 기술로, 앞 단의 로드밸런서를 통해 클라이언트 요청을 처리하여 성능 저하를 일으킬 수 있는 특정 서버의 과부하 방지, 다운된 서버를 제외한 나머지 서버로 요청 전달, 추가된 새로운 서버로 요청 전달 등의 기능을 수행할 수 있다.

     


    3. nginx 디렉토리 살펴보기

    nginx의 디렉토리를 살펴보며 어떤 것들이 있는지 확인해 보자. nginx의 기본설정들은 /etc/nginx에 있기 때문에 해당 디렉토리로 우선 이동해보도록 하자.

    cd /etc/nginx

    이동해서 파일 목록을 살펴보면, 다음과 같은 목록들이 나타날 것이다. 공부하는 입장이니. 하나씩 살펴보도록 하자

     

    3-1. uWSGI / fastCGI / SCGI(Common Gateway Interface)

    과거에는 정적인 HTML 위주로 서비스했던 시절이 있었다. 그러다 점점 더 많은 사람들이 웹을 사용하게 되면서, 다채로운 정보를 HTML을 통해 제공하고자 하는 움직임이 나타나기 시작했다. 그러나 수 많은 웹 페이지들을 직접 만드는 것은 한계가 있었고, 사용자가 입력한 데이터들을 받아서 서비스하기엔 '웹 서버'만으로는 불가능했다.

     

    이에 등장한 것이 바로 CGI이다. CGI는 웹 서버와 WAS(Web Application Server) 사이에 존재하는 규격화된 약속으로 서로 문제없이 소통할 수 있도록 하는 인터페이스이다. 즉, 다양한 언어로 쓰여진 WAS와 소통할 수 있게 된 것이다. 만약, 사용자가 요청한 정보가 단순 정적인 HTML 파일이 아니라 동적인 것이라면, 웹 서버는 자신이 처리할 수 없다는 사실을 인지하고 CGI 통신이 가능한 CGI 서버(uWSGI, fastCGI, SCGI 등)를 통해 WAS에 전달하게 된다. 이후 인터프리터는 읽은 결과를 CGI 서버를 통해 웹 서버에 돌려주고, 웹 서버는 해당 정보를 웹 브라우저에 띄우게 된다. 이처럼 CGI는 커뮤니케이션 과정에서 중요한 역할을 한다. 즉, 우리는 이를 통해서 Apache나 nginx와 같은 웹 서버를 사용하면서, Python이나 Javascript, PHP와 같은 다양한 어플리케이션을 붙여 쓸 수 있게 된 것이다.

    주의해야할 점은, 각 CGI 규칙의 이름들과 각 CGI 서버의 이름이 굉장히 헷갈릴 수 있다.

    CGI 규칙 : WSGI, Rack, PSGI 등
    CGI 서버 : uWSGI(Python), fastCGI, SCGI 등

    3-2. koi-utf, koi-win, win-utf

    해당 파일들은 문자셋이다. 현재는 잘 사용하지는 않으나, 뭐 용량도 그렇게 크지도 않고. 사용하는 소수의 사용자들이 있어 남겨두었다니. 그냥 넘어가도록 하자.

    3-3. mime.types(Multipurpose Internet Mail Extensions)

    과거에는 텍스트만으로 이루어진 파일을 주고 받는데 있어서 ASCII 표준만 따르면 문제가 없었다. 하지만, 네트워크를 통해서 이미지나 오디오와 같은 파일을 보내고자 하는 목적이 생기면서, 이러한 파일들을 바이너리 형태의 텍스트로 변환하는 것이 필요해졌다. 이에 이미지와 같은 파일을 인코딩하고 MIME 타입을 같이 명시해 수신자 측에 보내게 되었고, 수신자 측에서는 인코딩 된 파일의 MIME을 확인해 어떤 타입인지 확인하고 그것대로 디코딩할 수 있게 되었다. 이처럼, mime.type은 원활한 통신을 위해서 고려된 것이다.

    3-4. nginx.conf

    nginx.conf 파일은 접속자 수, 동작 프로세스 수 등 퍼포먼스에 관한 기본적인 설정 들을 담고 있다.

    3-5. sites-available / sites-enabled

    우선, 해당 폴더들이 무엇인지 알기 위해서는 '가상 호스팅(Virtual Hosting)'에 대해서 알아야 한다. 가상 호스팅이란, 하나의 서버에 여러 개의 도메인 이름을 호스팅하는 방식을 말한다. 이를 테면, 아래의 그림처럼. "http://egoing.net", "http://deving.net"으로 접속했을 때, 둘 다 1.226.82.52 IP를 가르키고, 1.226.82.52 IP에 해당하는 호스트가 각각의 도메인에 따라서 서로 다른 페이지를 서비스할 수 있게 한다.

    출처 : 생활코딩

    해당 폴더들은 위와 같은 가상 호스팅 환경과 관련한 것들이다. 가상 호스팅을 사용하거나 사용하지 않던 간에 그에 대한 설정들이 위치해있다. sites-available의 경우, 추후 사용할 수도 있는 비활성화된 사이트들의 설정 파일이 위치한 디렉토리이다. sites-enabled의 경우에는 sites-available에 있는 설정 중, 실행시키고 싶은 파일을 심볼릭 링크로 연결한 폴더이다. 실제로 이 폴더에 위치한 가상 호스팅 환경 파일들을 nginx.conf에서 읽어들여 서버를 세팅한다.

    * 여기서 심볼릭링크란, 특정 파일이나 디렉토리에 대하여 참조를 하는 특수한 파일임. Windows에서 우리가 사용하는 바로가기와 동일하다고 볼 수 있음. 사용하는 방법은 "ln -s /etc/nginx/sites-available/가상 호스트 파일명 /etc/nginx/sites-enabled/가상 호스트 파일명"으로 사용 함. 심볼릭 링크 걸어 둔 후, nginx를 재시작하면 된다.

    * 그냥, nginx.conf 하단에 있는 virtual host 블럭에 추가하면 안되는가? 그렇게 해도 됨. 하지만, 가독성이 떨어지고 설정 파일이 지저분하니 추천하지는 않는다.

    * 해당 기능을 사용하는 이유 중에 하나는, 도메인이 example.com인 경우 www.example.com 으로도 접속가능하게 하기 위해 사용한다.


    4. nginx.conf 살펴보기(생활코딩 참고)

    4-1. 기본정보

    user는 nginx 프로세스가 실행되는 권한을, worker_processes는 nginx 프로세스 실행 가능 수를, pid는 nginx의 마스터 프로세스 ID 정보가 저장되는 곳을 의미한다.

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;

    4-2. http 블록

    htp 블록 이후에 소개할 server, location의 루트 블록이라고 할 수 있고, 여기서 설정된 값을 하위 블록들이 상속한다. http 블록은 여러 개를 사용할 수 있지만 관리 상의 이슈로 한 번만 사용하는 것을 권장한다.

     

    http, server, location 블록은 계층 구조를 가지고 있다. 많은 지시어가 각각의 블록에서 동시에 사용할 수 있는데, http의 내용은 server의 기본 값이 되고, server의 지시어는 location의 기본 값이 된다. 그리고 하위의 블록에서 선언된 지시어는 상위의 선언을 무시하고 적용된다.

    4-3. server 블록

    server 블록은 하나의 웹 사이트를 선언하는데 사용된다. 이는 가상 호스팅의 개념이라고 할 수 있다. 예를 들어, 하나의 서버로 http://opentutorials.orghttp://egoing.net을 동시에 운영하고 싶은 경우에 사용될 수 있다. 가상 호스팅에 대해서는 위에서 이미 다루었으니 넘어가도록 한다.

    4-4. location 블록

    location 블록은 server 블록 안에 등장하면서 특정 URL을 처리하는 방법을 의미한다. 이를테면, opentutorials.org/course/1opentutorials.org/module/1 로 접근하는 요청을 다르게 처리하고 싶을 때 사용한다.

    4-5. events 블록

    이벤트 블록은 주로 네트워크의 동작 방법과 관련된 설정 값을 가진다. 이벤트 블록의 지시어들은 이벤트 블록에서만 사용할 수 있고, http, server, location과는 상속관계를 갖지 않는다.


    5. 간단한 예제코드

    해당 예제코드들에 대해서 자세히 살펴보고 싶다면 여기를 클릭해 주세요.

    5-1. 정적 파일 서빙하기

    http {
    	server {
        	location /html {
            	root /path/to/html;
            }
            
            location /image {
            	root /path/to/image;
            }
        }
    }

    5-2. 프록시 서버로 사용하기

    http {
    	server {
        
        	listen 80; #default는 80번 포트로 세팅되어있음
            
        	location / {
            	proxy_pass http://localhost:80;
            }
        }
    }
    
    
    # nginx 프록시 → CGI서버 → WAS에서 사용할 때
    
    http {
      server {
        listen 8080;
    
        uwsgi_param HTTPS $https if_not_empty;
        # HTTPS 라는 parameter 에 $https 값을 담는다.
        # (if_not_empty 를 적으면 비어있을 경우 전달하지 않는다.)
    
        location / {
          include uwsgi_params;      #uwsgi_param 을 전달한다.  
          uwsgi_pass http://localhost:8080;
        }
    
      }
    }

    5-3. 로드밸런서로 사용하기

    http{
    
      # load balancing 할 서버 그룹을 정의한다.
      upstream servergroup1 {
        # load balance 기법을 정한다.
        ip_hash;
    
        # 서버 (주소+port+[옵션])를 나열한다.
        server srv1.example.com:80;
        server srv2.example.com:3030 weight=3;
        server srv3.example.com;
      }
    
      # 프록시 서버로서의 nginx 동작을 기술한다.
      server {
        listen 80;
    
        location / {
          proxy_pass http://servergroup1 ; #(프로토콜명+로드밸런싱 그룹 이름)을 적어주면 된다
        }
      }
    
    }
    

    5-4. 프록시 요청 Timeout 늘리기

    http{
      server {
          ...
    
          location / {
              proxy_connect_timeout 300s;
              proxy_send_timeout 300s;
              proxy_read_timeout 300s;
              send_timeout 300s;
          }
      }
    }

    5-5. 클라이언트 업로드 파일용량 수정하기

    http{
      server {
        server_name nextop.com;
        listen 80;
        # 용량 업로드 제한 : default=10M
        client_max_body_size 20M;
    
        location / {
          ...
        }
      }
    }

    'Tech > Backend' 카테고리의 다른 글

    Node&Nginx를 PM2로 배포하기  (0) 2020.03.20
    Cache  (0) 2019.12.27
    Proxy  (2) 2019.12.24

    TAG

    댓글 0

Designed by Tistory.