HAProxy 와 Nginx 의 로드밸런싱

NGINX

Nginx 는 대표적인 웹서버인 Apache 의 문제점을 해결하면서 만들어진 웹서버로 비동기 방식으로 개발되어 가볍고 빠른 것으로 유명한 오픈소스 어플리케이션이다. Nginx 는 http 나 reverse proxy 같은 기능 외에도 load balancer 기능 또한 강력하다.

# Load Balancing
upstream target-server {
  least_conn;
  server [서버주소1] weight=5 max_fails=3 fail_timeout=10s;
  server [서버주소2] weight=10 max_fails=3 fail_timeout=10s;
}

server {
  listen 80;
  listen [::]:80;

  server_name front.local;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  location / {
    proxy_next_upstream error http_503;
    proxy_pass http://target-server;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header Host $host;
    proxy_redirect off;
  }
}

Nginx 로드 밸런싱은 upstream 이라는 옵션으로 설정할 수 있는데, least_conn 은 연결이 가장 적은 서버로 트래픽을 전달하는 역할을 한다. 설정할 수 있는 옵션은 다음과 같다.

옵션 설명
p_hash 같은 방문자로부터 도착한 요청은 항상 같은 업스트림 서버가 처리 할 수 있게 한다.
weight=n 업스트림 서버의 비중을 나타낸다. 이 값을 2로 설정하면 그렇지 않은 서버에 비해 두배 더 자주 선택된다.
max_fails=n n으로 지정한 횟수만큼 실패가 일어나면 서버가 죽은 것으로 간주한다.
fail_timeout=n max_fails가 지정된 상태에서 이 값이 설정만큼 서버가 응답하지 않으면 죽은 것으로 간주한다.
down 해당 서버를 사용하지 않게 지정한다. `ip_hash;` 지시어가 설정된 상태에서만 유효하다.
backup 모든 서버가 동작하지 않을 때 backup으로 표시된 서버가 사용되고 그 전까지는 사용되지 않는다.

출처: 생활코딩

다만, Nginx 의 유료 버젼인 Nginx Plus 를 사용하지 않는 이상 헬스체크가 불가능하기 때문에 실제 서버의 상태를 체크하는 API 를 만들어서 상황에 따라 스위칭하는 고가용성을 위한 동작에는 용이하지 않다.

HAProxy

Haproxy 는 L4, L7 과 같은 하드웨어 로드밸런서를 대체하기 위한 오픈소스 소프트에어로 이름처럼 Reverse Proxy 를 기반으로 로드밸런싱을 하기에 매우 강력하고 또 가벼운 어플리케이션이다. HA (High Availability) 라는 이름처럼 고가용성을 위하여 설계되었다. Nginx 로드밸런싱과 다른 점은 헬스체크라고 볼 수 있는데, 특정 API 에 접근하여 서버 상태를 점검하고, 문제가 있으면 다른 node 로 트래픽을 넘겨줄 수 있는 기능을 한다.

global
  log /dev/log 	local0
  log /dev/log 	local1 notice
  chroot /var/lib/haproxy
  user haproxy
  group haproxy
  daemon

defaults
  log  	global
  mode 	http
  option       	httplog
  option       	dontlognull
  timeout connect 5000
  timeout client 5000
  timeout server 5000
  errorfile 400 /etc/haproxy/errors/400.http
  errorfile 403 /etc/haproxy/errors/403.http
  errorfile 408 /etc/haproxy/errors/408.http
  errorfile 500 /etc/haproxy/errors/500.http
  errorfile 502 /etc/haproxy/errors/502.http
  errorfile 503 /etc/haproxy/errors/503.http
  errorfile 504 /etc/haproxy/errors/504.http

listen stats
  bind *:70
  stats enable
  stats uri /?stats=this-is-stats

frontend load-balancer
  bind *:80
  mode http
  acl my-url hdr(host) -i front.local
  http-request deny if !my-url
  default_backend server

backend server
  mode http
  option forwardfor
  # 헬스체크
  option httpchk GET /
  http-check expect status 200
  default-server inter 1s fall 3 rise 2
  # 로드 밸런싱
  balance roundrobin
  server server-blue [서버주소1] check
  server server-green [서버주소2] check

로드밸런싱은 Nginx 와 동일하게 round-robin 으로 설정했고, health check 는 특정 url 에 http status 코드를 설정하여 간단하게 적용할 수 있다. acl 옵션을 통해 access control 도 간단하게 처리할 수 있고, nginx 의 deny 기능 또한 유사한 형태로 간단하게 처리할 수 있다. 또한 haproxy 는 stats 이라고 하는 페이지를 기본적으로 제공하는데, 어떤 서버에 접속되고 작동하고 있는지 확인하기 편리하다. 단, uri 가 공개되면 곤란하니 방화벽으로 제한하거나, .htpasswd 같은 방식을 사용할 것.

마지막으로 헬스체크에 대해 조금 더 자세하게 설명하면, default-server inter 1s fall 3 rise 2 라고 하는 것은 다음과 같이 해석할 수 있다. 1초 마다 서버에 접속하여 헬스체크를 행하되 3번 실패하면 접속 불가로 판단하고 2번 성공하면 정상 상태로 간주하여 트래픽을 연결해준다. option httpchk GET / 은 http GET 으로 [서버주소]/ 요청을 날려서 http-check expect status 200 에 따라 200 OK 에 해당하는 응답이 나올시 정상 상태라고 판단하게 된다.

결론

간단하게 Nginx 와 HAProxy 의 로드밸런싱에 대해서 알아보았다. Nginx 자체의 로드밸런싱도 훌륭하지만, 굳이 웹 서버로서의 역할이 필요가 없다면 (캐싱이라거나 캐싱, 혹은 캐싱이라거나...) HAProxy 로드 밸런싱이 헬스체크가 가능하기도 하고 좀 더 가벼우니 필요에 따라 선택하면 좋을 것이다. 단, SSL 을 사용해야 하는 경우 HAProxy 는 1.5 버젼 부터 지원하니 꼭 잊지 말자. 삽질 엄청 함