처음하는 Nginx

김범식·2023년 4월 15일
0
post-thumbnail

Nginx 란

nginx는 간단하게 말하면 경량 웹서버이다. 클라이언트로 부터 요청을 받을 때 요청에 맞는 정적 파일을 응답해주는 Http web server로 활용되기도 하고, Reverse Proxy Server 로 활용하여 was 서버의 부하를 줄일 수 있는 로드 밸런서로 활용되고 도한다.





Apache서버와 다른점


Apache 와 같은 웹서버는 클라이언트로 부터 받은 요청을 처리할 때 새로운 프로세스 또는 쓰레드를 생성하여 처리한다 요청마다 쓰레드가 생성되므로 접속하는 사용자가 많으면 그만큼 쓰레드가 생성되어 cpu와 메모리 자원 소모가 커진다.

Nginx는 Event-Driven구조로 동작한다. 때문에 한개 또는 고정된 프로세스만 생성하여 사용하고, 비동기 방식으로 요청들을 Concurrency하게 처리할 수 있다. 위의 그림에서 보듯이 Nginx는 새로운 요청이 들어오더라도 새로운 프로세스와 쓰레드를 생성하지 않기 때문에 프로세서와 쓰레드 생성 비용이 존재하지 않고 적은 자원으로도 효율적인 운용이 가능하다 이러한 Nginx의 장점 덕분에 단일 서버에서도 동시에 많은 연결을 처리할 수 있다.




Nginx의 구조


nginx 는 하나의 master Process와 다수의 workerProcess로 구성되어 실행된다. master process는 설정 파일을 읽고 유효성을 검사한다. 그리고 worker Process를 관리한다. 모든 요청을 worker Process가 처리한다. nginx는 이벤트 기반 모델을 사용하고, worker process 사이에 요청을 효율적으로 분배하기 위해 os에 의존적인 메커니즘을 사용한다. (이는 하나의 요청을 처리하는 동안 다른 요청을 처리할 수 있도록 os 수준에서 비동기 방식으로 작업을 수행하는 것이다. ) worker process 의 개수는 설정 파일에서 정의되며, 정의된 프로세스 개수와 사용가능한 cpu코어 숫자에 맞게 자동으로 조정 된다.





nginx 설정


설정파일 구조

nignx는 지시어에 부여하는 값에 의해 작동한다. nginx의 메인 설정 파일경로는 /etc/nginx/nginx.conf 이다. (없다면 /usr/local/nginx/conf/nginx.conf , /usr/local/etc/nginx/nginx.conf 에 위치한다.)

nginx 모듈의 동작은 configuration 파일에 있는 directive(지시어)제어 된다. directive는 simple directiveblock directive 두가지 종류가 있습니다.





simple directive : 이름, 값이 있고 세미콜론(;)으로 끝난다

worker_process 1;

worker_process auto; //nginx가 자동으로 worker_process개수를 결정한다.
worker_cpu_affinity auto; //nginx가 자동으로 worker_process의 cpu 코어를 결정한다.






block directive : simple directive의 구조에 블록({}) 을 감싼 형태의 지시어이다.

events{
	worker_connections 1024;
}

이 블록 지시어는 하나의 worker_process가 몇개의 클라이언트를 받을 수 있는지 명시해준다.컴퓨터 성능에 따라 조절할 수 있으며 auto_scaling같은 기능은 지원하지 않는다.

block directive 는 해당 directive안에 또다른 block directive가 포함 될 수 있다

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

		location /images/{
			root /path/to/image ;
			}

		}
}

들어오는 경로마다 매핑해주는 정적 파일의 경로가 다르다.

include 지시어는 특정 파일을 포함하는 기능을 수행한다. 파일의 내용은 지시어가 있는 바로 그 위치에 해당 파일 내용이 삽입된다.

http{
	# mine.type 파일을 읽어들인다. (단일 파일을 include)
	include /etc/nginx/mime.types;

	# /etc/nginx/conf.d 디렉토리 아래 있는 .conf 파일을 모두 읽어 들임 
  # (특정 디렉토리의 모든 파일을 include)
	include /etc/nignx/conf.d/*.conf ;	
}






여기서 mine.types란?

types {
    text/html      html htm shtml;
    text/css       css;
    text/xml       xml;
    text/plain     txt;
    ...
}

server {
    listen       80;
    server_name  example.com;
    root         /var/www/example.com;

    location / {
        index  index.html index.htm;
    }

    location /docs/ {
        # /docs/ 디렉토리 내의 모든 .txt 파일에 대해
        # "Content-Type: text/plain" 응답 헤더를 추가함
        types {
            text/plain txt;
        }
    }
}

location /docs에 요청이 들어왔을 때, 보내줄 데이터 타입을 다음과 같이 지정할 수 있다. 위 코드에서는 `/docs/**** 경로에 있는 모든.txt파일에 대해서‘context-Type : text/plain’` 응답 헤더를 추가하도록 설정한 것이다.

이 타입들의 모음이 바로 mime.types 이다.





mime.type 사용하기

http {
    include       mime.types;   #대부분의 확장자명에 대한 타입이 들어있다.
    default_type  application/octet-stream;

  
  

server {
    listen       80;
    server_name  example.com;
    root         /var/www/example.com;

    location / {
        index  index.html index.htm;
    }

    location /docs/ {
        
    }
}
}

만약 우리가 클라이언트에 대한 응답으로 html 파일을 보내야 할 경우가 생길 때 nginx에서 그 파일의 확장자인 .html을 읽어서 mime.types에 저장되어있는 text/htmlcontent-Type으로 설정한다.

혹시라도 mime.types에 없는 확장자로 응답하려고 하면 default_type으로 설정된다.





지시어에 값에 사용되는 약자

k 또는 K : 킬로바이트
m 또는 M : 메가바이트
ms : 밀리초
s : 초
m : 분
h : 시
d : 일
w : 주
M :(30)
y :(365)

시간의 기본단위는 초이다.

이래 3가지 지시어는 모두 같은 값을 갖는다. 기본단위는 초이다.

client_body_timeout 3m;
client_body_timeout 180s;
client_body_timeout 180;






문자열값

지시어 값으로 사용되는 문자열 값은 ‘ 또는 “ 을 사용하지 않고 문자열을 나타낼 수 있다. 하지만 공백문자, 세미콜론(;), 중괄호 등 특수 문자를 사용하기 위해서는 ‘ 또는 “ 으로 문자열을 감싸서 지시어를 선언해야 한다.





메인설정


user nignx;

worker_process 1; 

error_log /var/log/nginx/error.log warn;

pid /var/run/nginx.pid;

events { 
	worker_connections 1024;
}

http{

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

	access_log /var/log/nginx/access.log main;
	
	sendfile on;

	keepalive_timeout 65;

	server_token off;
 
  include /etc/nginx/conf.d/*.conf;
}






각 코드에 대한 설명 추가}

#worker 프로세스를 실행할 사용자 설정
#_ 이 사용자에 따라 권한이 달라질 수 있다. 
# 만약 os가 ubuntu 라면 자신의 이름을 'whoami' 명령어를 통해 알수 있다. 여기서는 nginx를 예로 들었다.
# user를 설정하지 않는다면 기본적으로 root사용자를 설정한다. 다만 보안에 취약하기 때문에 user를설정하는것이좋다.
user nignx;

#실행할 worker 프로세스 설정
# - 서버에 장착되어 있는 코어 수 만큼 할당하는 것이 보통, 더 높게도 설정가능
worker_process 1; 
#worker_process auto; //nginx가 자동으로 worker_process개수를 결정한다.
#worker_cpu_affinity auto; //nginx가 자동으로 worker_process의 cpu 코어를 결정한다.

#오류 로그를 남길 파일 경로 지정
error_log /var/log/nginx/error.log warn;

#NGINX 마스터 프로세스 ID 를 저장할 파일 경로 지정
pid /var/run/nginx.pid;
# - 마트터 프로세스틑 서버당 하나만 존재한다.
# - pid 파일은 마스터 프로세스의 id를 저장하는 파일로, nginx중지하거나 재시작 할 때 사용된다. 
# - 마스터 프로세스 ID가 없다면 nginx를 중지하는 방법은 kill 명령어를 사용하는 방법 뿐이다. 
#중지(stop): sudo kill -s QUIT $(cat /var/run/nginx.pid)
#재시작(restart): sudo kill -s HUP $(cat /var/run/nginx.pid)

#접속 처리에 관한 설정을 한다. 
events { 
	# 워커 프로세스 한 개당 동시 접속 수 지정 (512, 1024를 기준으로 지정)
	worker_connections 1024;
}

 

# 웹, 프록시 관련 서버 설정
http{
	#mime.type파일을 읽어들인다. 
	include /etc/nginx/mime.types;
	#mime 타입 설정
	default_type application/octet-stream;

	# 엑세스 로그 형식 지정
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

# $remote_addr: 클라이언트의 IP 주소 
# $remote_user: 인증된 사용자 이름 (일반적으로 사용되지 않음)
# [$time_local]: 요청이 발생한 로컬 시간 (서버의 시간대를 기준으로 함)
# "$request": 클라이언트의 요청 정보 (메서드, URL, HTTP 프로토콜 버전)
# $status: 서버의 응답 상태 코드 (200, 404, 500 등)
# $body_bytes_sent: 응답으로 전송된 바이트 수
# "$http_referer": 이전 페이지의 URL (HTTP 리퍼러)
# "$http_user_agent", "$http_x_forwarded_for" : 클라이언트의 브라우저 정보, 프록시 서버를 거칠 경우 클라이언트의 ip 주소 정보를 포함시킬 수 있다.

	#엑세스 로그를 남길 파일경로 지정
	access_log /var/log/nginx/access.log main;
	
	#sendfile api 를 사용할지 말지 결정
	sendfile on;
	#tcp_nopush on;
#sendfile off 를 하는것은 nginx의 파일시스템 콜 대신 read/write시스템 콜을 사용하여 파일을 전송하게 된다. 
# 이경우 정적 파일(html, css, js등)은 전송 가능하지만, sendfile을 사용하는것보다 처리속도가 느릴 수 있다. 
# 또 sendfile을 사용하는 경우보다 cpu및 메모리 사용량이 증가할 수 있다. 
# 결론 :sendfile on으로 해놓는게 좋다. 

	# 접속시 커넥션을 몇 초동안 유지할지에 대한 설정
	keepalive_timeout 65;
	# 서버와 클라이언트간의 커넥션이 유지되는 동안 클라이언트는 추가요청을 보낼 수 있다. 이를 통해 다수의 요청에 대한 대기 시간을 단축시키고 tcp 세션의 지연시간을 줄일 수 있다.
  # 기본시간은 75초이다. 너무 짧으면 커넥션을 계속 다시 생성해야하고, 너무 길면 리소스를 낭비하게 됩니다.

  # (추가) nginx 버전을 숨길 수 있다. (보통 아래를 사용해서 숨기는게 일반적이다. )
	server_token off;
	# nginx의 버전을 숨기지 않으면 http 응답 해더에서 서버의 이름과 버전정보가 포함된다. 
	# 보안에 좋지 않다. 

	#gzip on;    
	#서버에서 보내는 응답 데이터를 압축하도록 지시하는 설정 => 응답속도 높이고 로딩속도를 대폭 절약할 수 있다. 
  # 브라우저는 알아서 gzip을 압축 해제하고 표시할 수 있다. 

 #/etc/nginx/conf.d 디렉토리 아래 있는 .conf 파일을 모두 읽어 들임
#다른설정파일도 가져와서 Main설정 파일과 병합하기 위함 
include /etc/nginx/conf.d/*.conf;
}






http 블록

http 블록은 http 부분과 관련된 모듈의 지시어와 블록을 정의하며, server와 location의 루트 블록이라고 할 수 있다. http, server, location블록은 계층구조를 가지고 있다.많은 지시어가 각 블록에서 동시에 사용될 수 있는데, http 블록의 내용은 server 블록의 기본값이 되고, server블로그이 내용은 location 블록의 기본값이 됩다.





server 블록

server 블록은 하나의 호스트를 선언하는데 사용하며, http블록 안에서만 사용할 수 있다. server블록에는 한개 이상의 location블록을 선언할 수 있다.





location 블록

location블록은 server 블록 안에 정의되며, 특정 url을 처리하는 방법을 정의한다. 예를 들면 http://example.com/1[http://example.com/world/1](http://example.com/world/1) 접근하는요청을 다르게 처리하고 싶을 때 사용한다.





events 블록

events 블록은 네트워크의 작동 환경을 설정하는 지시어를 제공한다. 이벤트 블록의 지시어는 이벤트 블록에서만 사용할 수 있고 http, server, local 블록과는 상속관계를 갖지 않는다. 아래 지시어들은 반드시 event 블록 안에서만 사용해야 합니다.

  1. accept_mutex
accept_mutex on;

accept_mutex 설정은 여러 워커 프로세스가 동시에 동일한 커넥션에 대한 요청을 받지 않도록 제어하는 역할을 한다.
 이 설정이 on으로 되어 있으면, 마스터 프로세스는 워커 프로세스들 사이에서 커넥션 요청을 위한 뮤텍스를 사용하여 동기화한다.
 이렇게 함으로써, 하나의 커넥션에 대한 요청은 하나의 워커 프로세스에서만 처리된다.
 따라서 accept_mutex 설정이 on으로 되어 있으면 서버의 안정성과 성능이 향상될 수 있다.

listen 소켓을 오픈하기 위한 accept 뮤텍스의 사용/해제를 설정한다.

accept_mutex 설정은 여러 워커 프로세스가 동시에 동일한 커넥션에 대한 요청을 받지 않도록 제어하는 역할을 한다. 이 설정이 on으로 되어 있으면, 마스터 프로세스는 워커 프로세스들 사이에서 커넥션 요청을 위한 뮤텍스를 사용하여 동기화한다. 이렇게 함으로써, 하나의 커넥션에 대한 요청은 하나의 워커 프로세스에서만 처리된다. 따라서 accept_mutex 설정이 on으로 되어 있으면 서버의 안정성과 성능이 향상될 수 있다.





있으면 좋은점

  1. accept_mutex off 설정일 때:
  • 워커 프로세스 중 한 프로세스가 클라이언트의 연결 요청을 받는다.
  • 이 프로세스는 바로 연결을 처리하기 위해 accept()를 호출하고, 다른 프로세스와의 경합 없이 연결을 처리한다.
  1. 이러한 상황에서 발생할 수 있는 문제점:
  • 여러 개의 워커 프로세스가 동시에 accept()를 호출하여 연결 요청을 처리하려고 시도할 수 있다.
  • 이로 인해 동일한 클라이언트로부터 여러 개의 연결이 발생할 수 있다.
  • 이는 워커 프로세스와 커넥션의 관리 및 성능 문제를 야기할 수 있다.
  1. accept_mutex on으로 해결하는 과정:
  • accept_mutex on 설정을 하면, 동시에 여러 개의 프로세스가 accept()를 호출하여 연결 요청을 처리하는 것을 방지한다.
  • 이를 위해 커널 레벨에서 뮤텍스를 사용하여 여러 개의 프로세스 간 경합을 막는다.
  • 따라서 하나의 프로세스만이 연결 요청을 처리하게 되고, 클라이언트는 하나의 커넥션만을 유지하게 된다.
  • 이는 커넥션의 관리와 성능 문제를 해결할 수 있는 장점을 갖게 된다.
  1. accept_mutex_delay
accept_mutex_daley 500ms

자원 획득을 다시 시도하기 전에 작업자 프로세스가 기다려야하는 시간을 정의한다.accept_mutex지시어가 off라면 이값은 사용되지 않는다.

하나의 워커프로세스가 다르프로세스에게 처리권한을 넘겨주기 전에 대기하는 시간을 지정하는 옵션이다.

  1. worker_connections
worker_connections 1024;

하나의 worker_Process가 동시에 처리할 수 있는 접속자 수를 정의합니다. worker_Processes * worker_connections = 최대 접속자 수




Reverse Proxy

nginx는 리버스 프록시 로도 활용할 수 있다. 리버스 프록시란 외부 클라이언트에서 서버로 접근시, 중간에 중재자 역할을 하여 내부 서버로 접근할 수 있도록 도와주는 서버다.

  • 보안 : 외부 사용자로 부터 내부망에 있는 서버의 존재를 숨길 수있다. 모든 요청은 리버스 프록시 서버에서 받으면 되고, 매핑되는 내부 서버로 요청이 전달된다. Nginx는 SSL 설정도 가능하다.
  • 로드밸런싱 : 리버스 프록시 서버가 내부 서버에 대한 정보를 알고있으므로, 각 서버의 상태에 따라 부하를 분산시키며 요청을 전달할 수 있다.





    Reverse Proxy 설정하기
http {
    server {
        listen 80;
        location / {
            proxy_pass http://127.0.0.1:8081;
        }
    }
}

listen을 지정하지 않으면 자동으로 80번으로 매핑된다.

참고 자료 : https://icarus8050.tistory.com/57

profile
frontend developer

0개의 댓글