Nginx

김준호·2022년 4월 26일
0

Nginx 를 사용하는 이유와 사용 방법을 정리
Nginx 를 설명하기 위해 Apache 를 설명하는 것으로 시작할 예정이니
Apache, Nginx 사용 이유에 관심이 없으시다면 우측 제목을 통해 'nginx 사용법'으로 Go!

Apache

현재 웹 서버 시장 점유율 1위를 기록하는 아파치
nginx 를 설명하기 위해서 아파치가 뭔지 알고 있으면 이해에 큰 도움이 된다고 생각함

  • 사용자 요청이 들어오면 커넥션을 형성하기 위해 프로세스를 생성함
    => 새로운 클라이언트의 요청이 들어올 때 마다 프로세스를 만듬
  • 프로세스를 생성하는 작업은 복잡하고 오래 걸리기 때문에 미리 프로세스를 만들어두고 요청이 들어오면 바로바로 할당해주는 prefork 방식을 사용하고 있음

전반적으로 로직 자체가 간단하기 때문에 개발하기 용이함
또한 모듈을 만들어서 기능을 추가하기도 원활한 구조였기에 확장성까지 좋은 그 당시 최고의 구조였음

아파치의 점유율은 날이 갈수록 증가했고 결국 아파치 서버 구조가 가져다주는 문제인 C10K 를 직면하게 됨
동시 커넥션 수가 1만개가 되었을 때 더이상 아파치 서버가 커넥션을 형성하지 못하는 문제
Connection 10000 problem => C10K

  • 요청이 들어올 때마다 프로세스를 생성하는 구조, 간단하지만 생성된 하나의 커넥션은 하나의 요청에만 국한되어버리는 단점은 요청이 많아질수록 프로세스가 수없이 많아졌고 결국 메모리 부족 현상으로 이어져버림
  • 또한 수없이 많아지는 프로세스를 작업하기 위해 context switching 이 급격하게 증가했고 이에 따라 cpu core 에 과부하가 걸릴 수 밖에 없었음
  • 모듈을 만들어서 기능을 추가하기 원활한 구조는 오히려 프로세스가 차지하는 리소스의 양을 늘리게 되는 결과를 초래함

Nginx

nginx 는 c10k 의 동시 커넥션이라는 문제를 해결하기 위한 구조로 되어 있음

Nginx 의 구조

How? 어떻게 nginx는 수많은 커넥션을 유지할 수 있는 것인가?

nginx의 구조는 마스터 프로세스로부터 시작
마스터 프로세스는 nginx의 설정값을 읽고 워커 프로세스를 생성함
이 워커 프로세스가 실제로 요청을 받고 처리하는 프로세스임

워커 프로세스는 생성될 때 socket을 배정받게 되고 이 소켓에 요청이 들어오면 커넥션을 형성하고 요청을 처리하게 됨
커넥션은 아파치 서버와 동일하게 keep-alive 를 통해 유지시킬 수 있음

중요한 것은, 아파치 서버와는 다르게 이미 생성된 커넥션을 하나의 요청만 한정해서 사용하지 않는다는 것
유지 중인 커넥션에 아무 요청이 없다면 다른 요청들을 가져와서 처리함
이 말은 곧 쉬지 않고 동작한다는 것을 의미하며 아파치 서버와 비교했을 때 요청이 없으면 방치되던 프로세스와는 다르니 서버 자원을 효율적으로 사용하게 되고, 이는 곧 메모리를 절약하는 장점을 얻을 수 있음(실제로 벤치마킹 해보면 동일 커넥션 대비 nginx의 메모리 사용률이 apache에 비해 현저히 낮음을 확인할 수 있다고 한다!)

위에서 설명한 nginx가 커넥션을 생성하고 요청을 처리하는 일련의 과정들을 이벤트라고 명칭함
nginx의 이벤트는 OS 커널이 큐 기반의 형식으로 워커 프로세스에게 전달되는데, 이 이벤트들은 큐에서 비동기 방식으로 워커 프로세스가 앞단의 이벤트를 처리할 때 까지 기다림

워커 프로세스의 갯수는 여러개 일 수 있으며, 각 프로세스를 만들어 놓음으로써 하나의 cpu core가 담당해야 하는 일련의 context switching 작업들을 분할할 수 있음.
auto 를 통해 nginx가 자동으로 설정해주는데, cpu core 갯수만큼 설정하는 것이 일반적이고 고성능 퍼포먼스를 위해 커스텀도 가능함

이와 같은 구조는 아파치에 비해 동시 커넥션을 유지하기에 용이할 수 밖에 없음

Apache vs Nginx

정답이 없다

아파치 역시 시대의 흐름에 맞춰 구조를 개선해왔고(ex: MPM, ..) 그에 따라 다양한 OS에 안정적이고 수많은 모듈에 커뮤니티까지 막대한 아파치는 현재에도 웹 서버 점유율 1위를 차지하고 있음

회사는 단 하나의 서비스보다는 여러 서비스를 제공할 것이며, 각 서비스의 모델에 맞는 구조를 선택하면 됨

Nginx 사용법

$ sudo service nginx start // 실행
$ sudo service nginx restart // 재실행
$ sudo service nginx stop // 정지
$ sudo service nginx status // 동작 상태
$ nginx -t // nginx 설정파일에 대한 문법 검사, nginx가 에러를 뿜을 때는 메세지를 정상적으로 출력하지 않기 때문에 이 명령어를 통해 어떤 부분에 오류가 있는지 확인할 수 있음

master, worker process

마스터 프로세스는 설정 파일을 읽고 워커 프로세스를 생성한다고 했었다.
이는 실제로 다음과 같이 확인 가능하다.
$ ps aux --forest | grep nginx

현재 정상적으로 nginx가 실행되고 있으며, 그에 따라 마스터 프로세스 밑에서 2개의 워커 프로세스가 동작하고 있음을 확인할 수 있다.

directive

simple directive, block directive 로 나뉘며 다음과 같음

// simple directive

// name value; 의 형태
// 세미콜론 빼먹지 말 것

worker_process auto;
// block directive

// context {
//	simple directive..
// 	context {
//		..
//	}
// }

events {
	worker_connection 768;
}
  • 설정 파일은 도메인(주제)별로 나누어서 모듈화 할 수 있으며 이 때는 include 를 block directive 내에 사용해서 작성한 로직을 불러올 수 있음
context {
	...
    include /etc/nginx/conf.d/*.conf;
}

nginx 사용 예시

ec2 ubuntu를 기반으로 작성

실행해보기

일단 nginx를 실행해보자
$ sudo service nginx start
그 후 잘 실행되고 있는지 체크해본다
$ sudo service nginx status

웹 서버 nginx을 실행했으니 curl을 통해서 접속이 잘 되는지 체크해보자
curl 127.0.0.1
nginx을 설치할 때 기본 셋팅이 되어 있었다면 아마 welcome nginx... 하는 index.html을 반환했을 것이다.
하지만 curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused 와 같은 에러를 뿜는다면, 이는 server block directive의 listen 소켓을 설정하지 않았기 때문이다.

이전 버전의 nginx는 정확히는 모르겠지만 최신 버전의 nginx는 /etc/nginx/sites-available/default 파일과 /etc/nginx/sites-enabled/default 파일이 심볼릭 링크로 연결되어 있기 때문에 둘 중 하나를 수정해주면 nginx.conf 에서 include 로 가져와 사용할 수 있게 된다

nginx 의 기본 위치는 /etc/nginx
$ cd /etc/nginx
/etc/nginx$ sudo vi sites-enabled/default
다음과 같이 작성해본다

server {
	listen 80; // default, nginx에서 설정한 어떤 포트로든 접근할 수 있고 ec2 같은 경우 포트 허용을 뚫어주면 실 ip로도 해당 포트에 접근할 수 있다.
}

nginx는 설정을 변경할 때마다 재실행 해줘야 한다
/etc/nginx$ sudo service nginx restart
다시 curl을 통해 nginx index.html이 잘 가져와지는지 확인해보자
/etc/nginx$ curl 127.0.0.1

이렇게 index.html 을 잘 가져오고, ec2 의 ip로 집적 접속해보면 다음과 같은 화면을 볼 수 있다.

server_name

server_name 은 특정 ip를 입력하거나 하는 귀찮음을 막고자 로컬 도메인을 설정해줌으로써 편하게 접근하도록 하기 위해 사용한다. (alias 같은 느낌)
/etc/nginx$ sudo vi sites-enabled/default 에서 server_name을 추가해보자

server {
	listen 80;
    server_name temp.com;
}

curl 명령어를 통해 설정해둔 server_name 으로 접근해보자
/etc/nginx$ curl temp.com
문법에 오류가 없다면 nginx index.html이 잘 가져와질 것이다.
크롬과 같은 브라우저에서는 temp.com으로 접근할 수 없다는 것은 당연한 것.

location

location 은 요청을 어디로 라우팅할 지 결정하는 block directive 로 server block directive 내에 존재해야한다.

/ 와 /hello 로 접속하는 요청을 구분해서 처리해보자
/etc/nginx$ sudo vi sites-enabled/default

server {
	listen 80;
    server_name temp.com;
    location / {
    	return 200 "This Page is Index.html\n";
    }
    location /hello {
    	return 200 "Hello world!!!\n";
    }
}

재실행 후 curl을 통해 /, /hello 로 접속해보자

nginx 는 요청에 대한 path를 prefix로 처리하기 때문에 /blabla로 요청해도 /에 대한 결과를 뿜을 것이다
엄격하게 path를 제어하고자 한다면 location = / { ...} 와 같이 설정해주면 된다

serve static file

nginx는 말그대로 웹 서버이므로 정적파일을 처리할 수 있다
특정 사용자가 /static/image.jpg 로 요청해서 image.jpg 파일을 제공받는 상황을 가정해서 설정해보자
/etc/nginx$ sudo vi sites-enabled/default

server {
	listen 80;
    server_name temp.com;
    location /static {
    	root /tmp;
    }
}

사용자는 /static/image.jpg/static 으로 정적 파일을 요청하도록 location을 설정해준다
그리고 location 내부의 root 는 /tmp 이라는 폴더에 대한 상위 prefix 위치값을 설정해준다
위의 경우 최종 경로는 /tmp/static 이라는 곳으로 접근하게 된다는 의미이다
실제로 저 경로를 만들고 정적파일 image.jpg를 제공할 수 있도록 예시 파일을 만들어보자
/etc/nginx$ cd /tmp
/tmp$ mkdir static
/tmp$ cd static
/tmp/static$ touch hello.txt
/tmp/static$ vi hello.txt <- 아무거나 작성
nginx 을 재실행하고 ec2 ip를 통해 ip/static/hello.txt 로 접속하면 파일이 제공되는지 확인해보자
(물론 curl 을 통해서도 가능)

reverse proxy

nginx가 제공하는 기능 중 하나로, 사용자가 어디로 접근하든지 간에 원하는 곳으로 위치시켜줄 수 있다. 이는 보안에도 유리하며 밸런싱을 통해 부하를 줄이는데에도 사용할 수 있다(로드밸런싱)
나는 ec2 에 react project를 clone 해 온 상태이니, 이 project 를 3000번 포트에서 실행시키고 특정 사용자가 요청했을 때 그 프로젝트를 서빙하는 것을 예시로 든다.
$ sudo vi /etc/nginx/sites-enabled/default

server {
	listen 80;
    ...
    location /project {
    	proxy_pass http://localhost:3000;
    }
}

/project 로 접근하면 알아서 http://localhost:3000 으로 다이렉트되는 것을 확인할 수 있다.
(만약 이렇게 프로젝트를 실행해서 접근하는 경우 지금까지 설정해둔 sites-enabled/default 내에 참조가 중복되서 프로젝트에 접근할 수 없는 경우가 생길 수 있다. /tmp 의 static 폴더를 삭제하고 설정파일의 참조 중복이 발생되는 코드를 삭제해주신 후 다시 시도해보면 잘 접근됨을 확인할 수 있다)

profile
추운 겨울 감기 조심

0개의 댓글