[nginx] 499 에러

nginx 2016. 6. 10. 20:07



nginx에서 499 에러가 발생했다. nginx를 연결하는 클라이언트에서 exception이 발생했을 것이다.

499는 nginx에서만 사용하는 cient closed request 상태 값이다. 

https://httpstatuses.com/499



문제를 해결하기 위해 nginx와 통신하는 클라이언트에서 http client timeout을 좀 길게 준다. (1초였다면 3초로)

Posted by '김용환'
,


nginx에서 파일을 이용하여 L7 health check (10초 동안 x번 200 리턴 값이 아닌 값이 나오면 l7 binding이 빠지게 하는 방법)하는 방법을 소개한다. 



1. -f을 이용하여 파일을 체크하는 방식이 있다. 

(사실 if가 evil이긴 하지만, 이 방법만큼 심플한 방법이 없었다..)


location = /l7.html {

  if (!-f /usr/local/nginx/off_health_check) {

    return 404; 

  }

  access_log  off;

  allow       all;


  proxy_pass http://service

}



/usr/local/nginx/off_health_check이 파일이 존재하지 않으면, 404을 리턴하여 l7 health check에 실패로 인식하게 한다.

만약 해당 파일이 존재하지 않으면 service 포트로 전달하도록 proxy_pass를 이용한다.


elasticsearch 라면, proxy_pass http://es/_cluster/health; 를 추가하여 elasticsearch의 클러스터 헬쓰 체크를 할 수 있도록 변경할 수 있다. 



참고 #1


nginx 공식 문서에, if (-f 파일명)에 대해서 좋지 않는 것 같다. 대신 try-files를 쓰라고 권고하고 있다.

https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#check-if-file-exists



Check (If) File Exists


Using if to ensure a file exists is horrible. It’s mean. If you have any recent version of NGINX you should look at try_files which just made life much easier.


BAD:


server {

    root /var/www/example.com;

    location / {

        if (!-f $request_filename) {

            break;

        }

    }

    

    






2. 설정 파일에서 읽어 l7 health check를 제어하는 방법이다.

if is evil!(https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/)이 찜찜하지만, 너무 좋은 기능이라 쓸 수 밖에 없다. 



설정 


<conf/l7.conf>

$ cat /usr/local/nginx/conf/l7.conf

set $l7 down;



<conf/vhost.conf 파일>


location /health_check.html {

include l7.conf;

if ($l7 = "down") {

return 404;

}


access_log  off;

        allow       all;


        default_type text/html;

        return 200 "OK";

        }





스크립트를 다음처럼 사용할 수 있다.


$ cat > l7.sh

#!/bin/sh


COMMAND=$1


if [ -z "${COMMAND}" ]; then

  echo 1>&2 "$0: no given command."

  exit 2

fi


echo "set \$l7 ${COMMAND};" > /usr/local/nginx/conf/l7.conf && sudo ./sbin/nginx -s reload && echo "${COMMAND}"




다음처럼 스크립트를 실행하면 l7 health check를 제어할 수 있다.


$ l7.sh up 

up

$ curl -v -XGET http://localhost/health_check.html

..HTTP/1.1 200 OK


$l7.sh down

down

.. HTTP/1.1 404 Not Found

    





* 노트 1

keepalive 모드를 사용하면서, l7.conf를 사용하여 변수 값을 이용하여 l7 health check하는 방법을 사용할 때, 이슈가 발생할 수 있다. nginx -s reload는 graceful하게 할 수 있다고 알려져 있지만, keepalive 모드에서는 tcp 데이터가 전달되면서 동시에 잠깐의 재시작이 일어나면서 패킷 드롭 현상이 발생될 수 있다.

no host exception과 같은 에러를 발견할 수 있다. 


이 문제를 해결하려면, keepalive를 쓰지 않거나, -f을 이용한 파일 체크를 사용하는 방법이 나을 것 같다. 





* 노트 2


keepalive 상태에서 파일을 이용한 l7 health check 방법은 약간의 한계가 있다. 

keepalive이기 때문에 대용량 서비스일 때, tcp 패킷이 계속 들어올 수 있기 때문에 l7 health check에서 200이 아닌 값, 즉 400 에러를 내보내도 계속 tcp 패킷이 들어와서 l7 스위치 바인딩에서 빠지지 않게 된다.


요청량이 아주 많지 않으면 keepalive를 쓰지 않는다. 그러면 파일을 이용한 l7 health check가 아주 유용할 것이다.

keepalive를 사용중이라면, client 쪽에서 여러 번 retry 구조로 변경해야 한다. 



* 노트 3

if (!-f 파일명) 


-f는 파일이 존재하면,

!-f는 파일이 존재하지 않으면 이라는 의미를 가진다.


!-f를 주로 사용하는 것이 추천하고 싶은 이유는 좀 더 유연하게 대처할 수 있을 것 같다. 

nginx를 재시작하기 전에 파일이 없으면 404라는 의미를 주는 것이 더 명쾌하는 것 같다. 



Posted by '김용환'
,


http://openresty.org/에 따르면, mac os x에서의 openresty 설치는 다음과 같다.



pcre와 openssl을 없다면 설치한다.


brew update

brew install pcre openssl



nginx 최신 버전을 설치하는 형태이다.

tar xvf ngx_openresty-VERSION.tar.gz

cd ngx_openresty-VERSION/

./configure

make

make install



실제로 해보니 mac os x에서 컴파일 에러가 발생했다.


wget https://openresty.org/download/openresty-1.9.7.3.tar.gz

./configure

make


이대로 했는데. make에서 컴파일 에러(nginx_openresty does not build under OSX)가 발생했다.

컴파일시 참조할 header(with-cc-opt)와 library (with-ld-opt)를 변경하면 문제가 없다.


./configure --with-cc-opt="-I/usr/local/include" --with-ld-opt="-L/usr/local/lib"

make 

sudo make install




참고로 -j 옵션을 주면 configure와 make 속도를 빨리할 수 있다. configure소스를 보면 core 개수를 의미한다. 



        if (defined $cores) {

            shell "${make} -j$cores$extra_opts PREFIX=$luajit_prefix", $dry_run;

        } else {

            shell "${make}$extra_opts PREFIX=$luajit_prefix", $dry_run;

        }




-j5을 옵션을 추가해 테스트를 해보니 확실히 조금 빠르긴 하다.


./configure --with-cc-opt="-I/usr/local/include" --with-ld-opt="-L/usr/local/lib" -j5

(기존 26초에서 15초로 줄어듬)


make -j5

(기존 38초에서 10초로 줄어듬)





참고 

http://openresty.org/

https://github.com/openresty/openresty/issues/3



Posted by '김용환'
,