Tagged: Nginx

Nginx 이용한 로드 밸런싱(Load Balancing) 구현하기

Nginx 는 전세계적으로 인기있는 웹 서버 입니다. 기존 웹 서버들과 달리 고속이며 대량의 접속을 적은 자원으로 처리해줍니다. 또, Nginx 는 Reverse Proxy 기능도 아주 훌륭하게 수행하며 이에 더해서 로드밸런싱 기능도 제공하는듯 다양한 기능을 다른 웹서버들보다 훌륭하게 수행합니다.

아키텍쳐(Architecture)

먼저 다음과 같은 아키텍쳐를 생각해 봅시다.

Nginx 로드 밸런싱 아키텍쳐

AWS 에 흔히 볼수 있는 기본적인 아키텍쳐입니다. 외부 접속은 External ELB가 담당하고 이것을 뒤에 Nginx 서버가 ELB의 접속을 받아서 Nginx 뒤에 있는 Jboss EAP 서버에 분배 접속을 하도록 하는 것입니다.

Nginx 로드 밸런싱(Load Balancing)

Nginx 는 자체적으로 로드 밸런싱 기능을 제공합니다. 이는 Nginx 의 Upstream 모듈을 통해서 제공 합니다. 기본적인 설정 방법은 다음과 같습니다.

ELB 에서 Nginx 로 80 포트(port)로 접속을하면 proxy_pass 에 정의된 upstream 인 myapp1 으로 연결을 시켜주며 myapp1 upstream 에 정의된 서버 3대 중에 하나에 연결을 시켜줍니다.

upstream 에서 다양한 옵션을 제공 합니다. 대표적인 것이 Nginx 뒤에 서버의 연결 상태를 어떻게 체크할 것인가 하는 것입니다. 예를들면,

srv1.example.com 서버는 30초 동안 최대 3번 접속이 실패하면 30초 동안 접속이 불가한 것으로 판단 합니다. 30초가 지나면 또 최대 3번의 접속 실패가 발생하고 나서야 30초동안 접속을 하지 않습니다.

지속적인 서비스를 제공해야하는 상황에서 접속이 잘되는지 안되는지 실제로 접속을 해봐야만 한다면 고객들에게 불편을 제공할 것입니다.

AWS ELB 방식

AWS ELB 방식은 위 Nginx 의 max_fails 방법과는 다릅니다. ELB 는 뒤에 연결되는 인스턴스(Instance)가 살았는지 죽었는지를 판단하는 Health Check 기능을 제공합니다. 이것은 5초에 한번 Health Check 를 하고 10번이상 성공했다면 인스턴스가 살았다라고 판단해(InService 상태) 연결을 활성화 해줍니다. 만일 5초에 한번 Health Check 를 하는데 2번 실패를 했다면 인스턴스가 죽었다고 판단해(OutOfService 상태) 더 이상 연결을 시도하지 않습니다.

즉, 일정한 기준을 만족해야만 연결을 활성화 해준다는 겁니다. Nginx 에서도 이렇게 동작하면 얼마나 좋을까?

nginx_http_upstream_check_module

nginx_http_upstream_check_module 모듈은 Nginx.org 에서 배포하지 않고 개인 개발자가 개발한 Third Party 모듈 입니다. 이 모듈은 앞에서 언급했던 ELB 의 Health Check 기능을 제공해 줍니다. 특정한 기준을 통과하면 연결을 활성화 시켜주는 것입니다.

이를 활용하기 위해서는 Nginx 설치시에 같이 컴파일 설치를 해줘야 합니다.

Nginx 설치

이번 Nginx 설치는 Upstream Health Check Module 를 함께 설치하는 과정을 포함 합니다.

설치 환경은 다음과 같습니다.

  • Ubuntu 14.04 64bit
  • 컴파일을 위해서 설치한 패키지들: build-essential, automake, unzip, patch, libpcre++-dev, zlib1g-dev, geoip-bin, libgeoip-dev

Nginx 다운로드를 해줍니다.

nginx_http_upstream_check_module 는 git를 이용해서 다운(?) 받습니다.

이제 Nginx 에 nginx_http_upstream_check_module 다음과 패치를 해줍니다.

그리고 다음과 같이 서버 Signiture 를 바꿔 줍니다.

이렇게하면 서버가 PowerServer/1.0 이라고 나와서 Nginx 를 쓴다는것을 숨길 수가 있습니다.

마지막으로 openssl 최신 소스를 다운받아 nginx 디렉토리에 놓습니다.

 

Nginx 설정하기

설치가 끝났다면 이제 설정을 해야 합니다. 설정에 앞서서 현재 Nginx 의 아키텍쳐를 상기시켜봅시다.

  • Nginx 앞에는 AWS ELB 에 있다. AWS ELB 는 실제 접속자인 Client IP 를 ‘X-Forewarded-For’ 헤더값에 저장해 넘겨준다.
  • Nginx 뒤에는 두대의 WAS 서버가 존재한다.
  • Nginx 는 뒤에 두대의 WAS 에 대해서 Health Check 하고 특정값 기준으로 Alive/Down 을 결정하도록 한다.

위 내용을 설정에 반영하면 다음과 같습니다.

먼저 7번째 줄에 Nginx 에서 실제 IP를 ‘X-Forewarded-For’ 헤더 값이라고 알려 주도록 설정한 것입니다. 8번째 줄은 AWS ELB 의 주소 범위를 말합니다. Nginx 는 AWS ELB 로부터 접속을 받기 때문에 그것을 지정해줄 필요가 있는데 그것이 바로 8줄 설정입니다. 12줄 ~ 14줄은 뒤에 WAS 서버에 넘겨줄 헤더값을 지정해주고 있습니다. WAS 서버도 실제 Client IP가 필요하기 때문에 이것을 ‘X-Forewarded-For’ 에 지정해 줍니다. 그외에 ‘X-Forewarded-Server’, ‘X-Forewarded-Host’ 도 지정해 줍니다.

18번째 줄부터는 이제 upstream 설정하는 부분인데, 24줄이 Health Checker 를 해주는 부분으로 nginx_http_upstream_check_module 기능 입니다. 3초에 한번 체크를 하는데 그 방법은 TCP를 이용하고 5번 연속으로 실패할 경우에 뒤에 서버는 다운된것으로 하고 2번 연속 성공하면 뒤에 서버가 살아있는것으로 해서 연결을 시켜줍니다. 마치 AWS ELB 처럼 동작하는 것입니다.

/status URL 을 호출하면 다음과 같이 나옵니다.

Nginx Upstream Health Status
Rise Counts, Fall counts 는 3초마다 체크해서 그 수를 센 것입니다. 현재 뒤에 WAS 서버들이 하나는 살아 있고, 하나는 죽은것으로 되어 있고 Down 된 서버는 빨강색으로 표시됩니다.

체크하난 프로토콜을 변경할 수 있는데, http 를 이용할 경우에 보내는 url 과 기대되는 리턴되는 http 의 상태값(status)를 지정해주면 됩니다.

Nginx 설정.

이 문서는 Nginx  설정에 대한 문서 입니다. 계속적으로 업데이트가 됩니다.

요청 메소드 제한

요청 메소드는 GET, HEAD, POST, PUT, DELETE 등이 있다. 문제는 대부분 웹 서비스는 GET, HEAD, POST 만 필요로한다는 것이다. Nginx 에서 이를 다음과 같이 제한 할 수 있다.

GZIP 설정

 

Nginx + PHP-FPM + MariaDB 설치 (CentOS 7)

과거에는 APM (Apache + PHP + MySQL)이 인기있는 플랫폼이 였지만 최근에는 Nginx 가 나오고 PHP-FPM 이 나오면서 NPM 으로 많이 대체되고 있는 추세에 있습니다. 이 글은 Nginx,PHP-FPM, MariaDB 설치에 관한 것입니다.

준비

이 글에서 NPM을 설치하는 환경은 다음과 같습니다.

  • CentOS 7.2.1511
  • X86_64
  • Selinux Disable
  • 작성시간: 2015. 12. 27

설치하는 방법은 CentOS 7 에서 제공하는 패키지 관리 프로그램인 YUM을 이용하는 것입니다. 다음과 같이 CentOS 7 를 최신 버전으로 만듭니다.

 

PHP 설치

다음과같이 YUM 을 이용해서 설치해 줍니다.

php-mysql 은 MariaDB 와 연동하기 위한 것임으로 함게 설치해 줍니다.

systemctl 에 등록하고 시작해 줍니다.

php-fpm 의 pool 설정을 다음과 같이 해줍니다.

세션(Session) 디렉토리의 소유권을 cacti 로 변경해 줍니다.

 

MariaDB 설치

MariaDB 의 최신 버전 설치를 위해서 다음과 같이 YUM 저장소를 추가해 줍니다. YUM 저장소 추가는 다음 내용을 파일로 저장해주면 됩니다.

현재 MariaDB 의 최신버전은 10.1 이기 때문에 baseurl 에 버전이 정확해야 합니다. 다음과 같이 설치를 해줍니다.

systemctl 에 등록을 해주고 데몬을 시작해 줍니다.

mysql_secure_installation 을 실행해서 root 패스워드와 불필요한 데이터베이스를 삭제 합니다.

 

Nginx 설치

Nginx 의 최신 버전 설치를 위해서 다음과 같이 YUM 저장소를 추가해 줍니다. YUM 저장소 추가는 다음 내용을 파일로 저장해주면 됩니다.

cacti 서비스를 예를들어 다음과 같이 cacti.conf 파일을 작성합니다.

웹 서비스를 위한 홈 디렉토리가 ‘/home/cacti’ 를 만들어주고 www 디렉토리를 생성해 줍니다.

nginx 문법체크를 하고 systemctl 에 서비스를 등록하고 서비스를 시작해 줍니다.

80(http) 방화벽 설정

80 포트, 즉 HTTP 를 위한 방화벽 설정을 다음과 같이 해줍니다.

 

 

Nginx KeepAlive

Nginx 에서 KeepAlive 관련된 설정은 다음과 같이 세가지이다.

  • keepalive_disable
  • keepalive_timeout
  • keepalive_requests

먼저, Keepalive 는 HTTP 와 TCP 상에서 구현되어 있다. HTTP 의 경우에는 1.0 버전과 1.1 버전이 존재하는데, 1.0 버전에서는 KeepAlive 는 존재하지 않으며 1.1 에서는 연결시에 기본으로 KeepAlive 가 활성화 된다.

HTTP 는 “Connetionless” 방법을 취한다. 웹 컨텐츠를 전송 받기 위해서 서버에 연결을 한 후에 데이터를 전송받는다. 그리고는 연결을 바로 끊게 된다. 하지만 웹이라는게 HTML, Javascript, CSS, Image 파일등으로 수백개로 이루어진 상태에서 수백의 컨텐츠를 전송하기위해서 연결을 수백번을 한다면 비 효율적일 것이다. 그래서 한번의 연결로 수십개의 컨텐츠를 전송하도록 해주는것이 KeepAlive 이다.

그렇다면 의문이 들 것이다. KeepAlive 를 켜주기만할 것이지 왜 timout, request 와같은 설정이 필요한 것일까?

답은 네트워크 상황이 좋지 않을때에 나타난다. 만약 KeepAlive 연결이 된상태에서 데이터 전송에 문제가 생겼을 경우 또는 Client 에서 데이터 전송을 하지 않을 경우에 이 연결된 접속은 어떻게 해야 할까? Server 접속 자원은 무한정이 아니기에 이러한 접속을 계속 유지되는 것은 Server 에 막대한 손실을 발생시키고 이는 곧 접속 장애로 이어진다.

그래서 접속이 이루어진 후에 컨텐츠를 전송받은후에 얼마간 또 다시 컨텐츠 전송 요청이 없다면 Server 가 접속을 차단시키도록 해야하는데 이것이바로 keepalive_timeout 이다. 다시말해 처음 접속이 이루어지고 컨텐츠를 한번 전송한 이후에 타이머를 실행시켜서 timeout 시간까지 Client 가 컨텐츠 요청이 없다면 Server는 접속을 차단하게 된다.

keepalive_request 는 Server 에 접속이 이루어진 이후에 컨텐츠를 요청한 갯수를 계산하고 이값을 넘으면 접속을 차단하는 것이다.

이렇게 접속이 차단되면 다음 번 컨텐츠 요청을 위해선느 새로운 접속이 이루어져야 한다.

그렇다면, Nginx 에서는 어떻게 이것을 다룰까? 이를 위해서는 먼저 Nginx 를 debug 모드가 활성화 되도록 컴파일 설치해야 한다.

그리고 다음과 같이 error_log 에 debug 를 활성화 해줍니다.

keepalive_timeout  설정을 5초로 해줍니다.

이렇게해서 nginx 를 실행하고 error.log 파일을 보면 nginx 가 처리하는 과정을 상세히 볼 수 가 있다.

이와 더불어 HTTP 연결 테스트는 Telnet 을 이용하면 된다. 테스트는 다음과 같이 진행하면 된다.

마지막에 “Connection close by foreign host.” 메시지는 5초동안 아무런 요청이 없으면 나타나는데 이는 keepalive_timeout 설정된 값과 같다. 만일 5초가 지나기 전에 또 한번에 데이터 요청을 Server 에 보낸다면 keepalive_timeout 은 reset 되고 전송이 끝난후에 다시 타이머가  흐르기 시작한다.

이는 keepalive_timout 에 대해서 데이터 전송이 끝난 후에 다시 데이터 전송 요청때까지의 갭타임을 의미하기도 한다. 그 사이에 데이터 전송 요청이 없다면 Server 가 접속을 차단하게 된다.

위 실험에서 Nginx는 과연 어떻게 처리했을까? 로그에는 아주 많은 정보가 표시되는데, 전송이 모두 끝난후에 다음과 같은 로그가 보인다.

Nginx 에서 timout 관련 설정은 거의 대부분 내부적으로 timer 로 처리 된다. Nginx 의 I/O Multiplexer 는 epoll 이기 때문에 내부적으로 epoll_wait 에 timer 가 전달되어 처리되는 구조다.

그리고 각각의 timeout 들은 내부적으로 처리하는 handler 가 존재해 처리된다. 각각의 handler 들은 timer 를 체크하고 close_connection 을 호출하는 방식으로 접속을 차단하도록 구현되어 있다.

“http keepalive handler” 는 ngx_http_request.c 에 구현되어 있다.

 

Nginx Gzip Compression 설정

HTTP 에서도 압축전송을 지원 합니다. 이는 Header 에 압축에 대한 정보가 다음과 같이 담깁니다. Nginx Gzip Compression 설정 은 다음과같이 하시면 됩니다.

압축전송을 하게되면 트래픽을 줄일 수 있어, 서버 호스팅을 이용하는 분들에게는 큰 도움이 됩니다. 사용법은 다음과 같습니다.

잘 동작하는지 다음과 같이 테스트를 할 수 있습니다.

“Content-Encoding: gzip” 이 보이면 정상으로 설정이 된 것 입니다.