nginx의 next_upstream이 완벽하게 HA를 제공하는지 테스트하는 예시이다.
다음 코드를 참조했다.
https://gist.github.com/bradmontgomery/2219997#file-dummy-web-server-py
#!/usr/bin/env python
"""
Very simple HTTP server in python.
Usage::
./dummy-web-server.py [<port>]
Send a GET request::
curl http://localhost
Send a HEAD request::
curl -I http://localhost
Send a POST request::
curl -d "foo=bar&bin=baz" http://localhost
"""
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer
class S(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_headers()
self.wfile.write("<html><body><h1>hi!</h1></body></html>")
def do_HEAD(self):
self._set_headers()
def do_POST(self):
# Doesn't do anything with posted data
self._set_headers()
self.wfile.write("<html><body><h1>POST!</h1></body></html>")
def run(server_class=HTTPServer, handler_class=S, port=80):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print 'Starting httpd...'
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
nginx 설정은 다음과 같다.
server {
listen 8888;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout invalid_header http_502 http_503 http_504;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
두 디렉토리에 각각 파이썬 simple web server 를 다운받고 포트를 각각 8080, 8081로 바꿔 개별 디렉토리에서 실행한다.
테스트를 해보면, 정상적으로 잘 동작한다. proxy_pass설정에 따라 처음은 8080, 다음은 8081로 잘 돌아가면서 동작한다.
$ curl http://localhost:8888
<html><body><h1>hi!</h1></body></html>
이번에는 8081포트로 실행한 파이썬 서버에서 GET을 호출시 503 헤더 응답을 보내도록 수정하고 다시 실행한다.
curl로 get 요청을 하나 보낸다.
127.0.0.1 - - [29/Dec/2016 20:51:05] "GET / HTTP/1.1" 503 -
내부적으로 문제가 발생한 것을 보고 8081 파이썬 서버로 GET을 보낸다. (retry 확인)
127.0.0.1 - - [29/Dec/2016 20:51:05] "GET / HTTP/1.1" 200 -
이번에는 8081포트로 실행한 파이썬 서버에 POST를 호출시 503 헤더 응답을 보내도록 수정한다.
http 요청이 8081에 전달되면 에러가 발생한다.
$ curl -X POST http://localhost:8888
<html><body><h1>POST!</h1></body></html>[/usr/local/nginx/conf] curl -X POST http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>An error occurred.</h1>
<p>Sorry, the page you are looking for is currently unavailable.<br/>
Please try again later.</p>
<p>If you are the system administrator of this resource then you should check
the <a href="http://nginx.org/r/error_log">error log</a> for details.</p>
<p><em>Faithfully yours, nginx.</em></p>
</body>
</html>
그리고 파이썬 서버에서는 에러가 발생했다.
127.0.0.1 - - [29/Dec/2016 11:56:48] "POST / HTTP/1.1" 503 -
그리고 retry는 되지 않는다. 비멱등 메소드는 retry를 지원하지 않는다.
의외로 nginx의 next stream(proxy_next_upstream)이 완벽한 L7 health check 대용으로 생각하는 분이 많다는 점이다.
1.9.12까지는 비멱등 메소드(POST, LOCK, PATCH)에 대해서 retry를 지원했으나, 1.9.13부터는 비멱등 메소드 호출시 retry를 해주지 않는다.
문서로 명시적으로 설명되어 있다.
http://nginx.org/en/CHANGES
Changes with nginx 1.9.13 29 Mar 2016
*) Change: non-idempotent requests (POST, LOCK, PATCH) are no longer
passed to the next server by default if a request has been sent to a
backend; the "non_idempotent" parameter of the "proxy_next_upstream"
directive explicitly allows retrying such requests.
참고로 proxy_request_buffering를 사용한다 하더라도 동일하다.