NGINX Plus

HTTP Load Balancing

NGINX Plus 의 여러 알고리즘과 Slow Start 및 세션 지속성과 같은 고급 기능을 사용하여 웹 또는 애플리케이션 서버 그룹 간에 HTTP 트래픽의 Load Balancing합니다.

목차

1. 개요
2. 서버 그룹에 HTTP 트래픽 Proxy하기
3. Load Balancing 방법 선택
4. 서버 가중치
5. 서버 Slow-Start
6. 세션 지속성 활성화
7. 연결 수 제한
8. Health Check 구성
9. 여러 Worker Process와 데이터 공유

9-1. Zone 크기 설정
10. DNS를 사용하여 HTTP Load Balancing 구성
11. Microsoft Exchange 서버의 Load Balancing
11-1. 전체 NTLM 예제
12. NGINX Plus API를 사용한 동적 구성

1. 개요

여러 애플리케이션 인스턴스에 걸친 Load Balancing은 리소스 사용률 최적화, 처리량 극대화, 지연 시간 단축, 내결함성 구성을 보장하기 위해 일반적으로 사용되는 기술입니다.

NGINX와 NGINX Plus는 다양한 배포 시나리오에서 매우 효율적인 HTTP Load Balancer로 사용할 수 있습니다.

2. 서버 그룹에 HTTP 트래픽 Proxy하기

서버 그룹에 대한 HTTP 트래픽 Load Balancing을 위해 NGINX Plus 또는 NGINX Open Source를 사용하려면 먼저 upstream 지시문을 사용하여 그룹을 정의해야 합니다. 이 지시문은 http 컨텍스트에 배치됩니다.

그룹의 서버는 server 지시문을 사용하여 구성됩니다(NGINX에서 실행되는 가상 서버를 정의하는 server 블록과 혼동하지 마세요). 예를 들어, 다음 구성은 backend라는 그룹을 정의하며 세 개의 서버 구성으로 구성됩니다(실제 서버는 세 개 이상일 수 있습니다).

http {
    upstream backend {
        server backend1.example.com weight=5;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }
}

서버 그룹에 요청을 전달하려면 그룹 이름을 proxy_pass 지시문에 지정합니다(또는 해당 프로토콜의 경우 fastcgi_pass, memcached_pass, scgi_pass 또는 uwsgi_pass 지시문에 지정합니다). 다음 예제에서는 NGINX에서 실행되는 가상 서버가 모든 요청을 이전 예제에서 정의한 backend upstream 그룹으로 전달합니다:

server {
    location / {
        proxy_pass http://backend;
    }
}

다음 예제는 위의 두 Snippet을 결합하여 backend 서버 그룹에 HTTP 요청을 Proxy하는 방법을 보여줍니다. 이 그룹은 세 대의 서버로 구성되며, 그 중 두 대는 동일한 애플리케이션의 인스턴스를 실행하고 세 번째 서버는 백업 서버입니다. upstream 블록에 Load Balancing 알고리즘이 지정되어 있지 않기 때문에 NGINX는 기본 알고리즘인 Round Robin을 사용합니다:

http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server 192.0.0.1 backup;
    }
    
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}

3. Load Balancing 방법 선택

NGINX Open Source는 네 가지 Load Balancing 방법을 지원하며, NGINX Plus는 두 가지 방법을 더 추가로 지원합니다.

1. Round Robin – 요청이 서버 가중치를 고려하여 서버 전체에 균등하게 분산됩니다. 이 방법은 기본값으로 사용됩니다(사용하도록 설정하는 별도의 지시문은 없습니다).

upstream backend {
   # no load balancing method is specified for Round Robin
   server backend1.example.com;
   server backend2.example.com;
}

2. Least Connections서버 가중치를 고려하여 활성화된 연결 수가 가장 적은 서버로 요청이 전송됩니다.

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

3. IP Hash – 요청이 전송되는 서버는 클라이언트 IP 주소에서 결정됩니다. 이 경우 IPv4 주소의 처음 세 Octet 또는 전체 IPv6 주소가 해시값을 계산하는 데 사용됩니다. 이 방법을 사용하면 동일한 주소의 요청은 해당 서버를 사용할 수 없는 경우가 아니면 동일한 서버로 전달됩니다.

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

서버 중 하나를 Load Balancing 로테이션에서 일시적으로 제거해야 하는 경우 클라이언트 IP 주소의 현재 해싱을 유지하기 위해 해당 서버를 down 매개변수로 표시할 수 있습니다. 이 서버에서 처리해야 할 요청은 자동으로 그룹의 다음 서버로 전송됩니다.

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
}

4. 일반 Hash – 요청이 전송되는 서버는 텍스트 문자열, 변수 또는 조합일 수 있는 사용자 정의 키에 의해 결정됩니다. 예를 들어 키는 쌍으로 연결된 소스 IP 주소와 포트 또는 이 예제처럼 URI일 수 있습니다.

upstream backend {
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
}

hash 지시문에 일관된 매개변수(선택 사항)를 사용하면 ketama 일관된 해시 Load Balancing을 사용할 수 있습니다. 요청은 사용자 정의 해시 키 값에 따라 모든 Upstream 서버에 균등하게 분산됩니다. Upstream 그룹에 Upstream 서버가 추가되거나 제거되면 몇 개의 키만 다시 매핑되므로 캐시 서버 또는 상태를 축적하는 기타 애플리케이션의 Load Balancing 시 캐시 손실이 최소화됩니다.

5. Least Time (NGINX Plus만 해당) – 각 요청에 대해 NGINX Plus는 평균 지연 시간이 가장 낮고 활성화된 연결 수가 가장 적은 서버를 선택하며, 평균 지연 시간이 가장 낮은 서버는 least_time 지시문에 대한 다음 매개변수 중 어떤 것이 포함되어 있느냐에 따라 계산됩니다.

  • header – 서버로부터 첫 번째 Byte를 전송 받는 시간
  • last_byte – 서버로부터 전체 응답을 받는 데 걸리는 시간
  • last_byte inflight – 불완전한 요청을 고려하여 서버로부터 전체 응답을 수신하는 데 걸리는 시간
upstream backend {
    least_time header;
    server backend1.example.com;
    server backend2.example.com;
}

6. Random – 각 요청은 무작위로 선택된 서버로 전달됩니다. 2 개의 매개변수를 지정하면 먼저 NGINX가 서버 가중치를 고려하여 두 개의 서버를 무작위로 선택한 다음 지정된 방법을 사용하여 이 서버 중 하나를 선택합니다.

  • least_conn – 활성화된 연결 수가 가장 적은 경우
  • least_time=header (NGINX Plus) – 서버로부터 응답 헤더를 전송받는 데 걸리는 최소 평균 시간 ($upstream_header_time)
  • least_time=last_byte (NGINX Plus) – 서버로부터 전체 응답을 전송받는 데 걸리는 최소 평균 시간 ($upstream_response_time)
upstream backend {
    random two least_time=last_byte;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
    server backend4.example.com;
}

여러 Load Balancer가 동일한 Backend 집합에 요청을 전달하는 분산 환경에서는 Random Load Balancing 방법을 사용해야 합니다. Load Balancer가 모든 요청을 전체적으로 파악할 수 있는 환경에서는 Round Robin, Least Connections 및 Least Time과 같은 다른 Load Balancing 방법을 사용하세요.

Note: Round Robin 이외의 다른 방법을 구성할 때는 upstream { } 블록의 server 지시문 목록 위에 해당 지시문( hash, ip_hash, least_conn, least_time 또는 random)을 넣습니다.

4. 서버 가중치

기본적으로 NGINX는 Round Robin 방법을 사용하여 가중치에 따라 그룹 내 서버에 요청을 분산합니다. server 지시문의 weight 매개변수는 서버의 가중치를 설정하며, 기본값은 1입니다.

upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

이 예에서 backend1.example.com의 가중치는 5이고 다른 두 서버의 가중치는 기본값(1)이지만 IP 주소가 192.0.0.1인 서버는 backup 서버로 표시되어 다른 두 서버를 모두 사용할 수 없는 경우가 아니면 요청을 수신하지 않습니다. 이 가중치 구성을 사용하면 6개의 요청 중 5개는 backend1.example.com으로, 1개는 backend2.example.com으로 전송됩니다.

5. 서버 Slow-Start

서버 Slow-Start 기능은 최근에 복구된 서버가 연결로 인해 과부하가 걸리는 것을 방지하여 시간 초과로 인해 서버가 다시 실패로 표시되는 것을 방지합니다.

NGINX Plus에서 Slow-Start를 사용하면 Upstream 서버가 복구되거나 사용할 수 있게 된 후 가중치를 0에서 원래 값으로 점진적으로 복구할 수 있습니다. 이는 server 지시문에 slow_start 매개변수를 사용하여 수행할 수 있습니다:

upstream backend {
    server backend1.example.com slow_start=30s;
    server backend2.example.com;
    server 192.0.0.1 backup;
}

시간 값(여기서는 30초)은 NGINX Plus가 서버에 대한 연결 수를 최대 값으로 늘리는 시간을 설정합니다.

Note: 그룹에 서버가 하나만 있는 경우 server 지시문의 max_fails, fail_timeout, slow_start 매개변수가 무시되고 서버를 사용할 수 없는 것으로 간주하지 않습니다.

6. 세션 지속성 활성화

세션 지속성이란 NGINX Plus가 사용자 세션을 식별하고 특정 세션의 모든 요청을 동일한 Upstream 서버로 라우팅하는 것을 의미합니다.

NGINX Plus는 세 가지 세션 지속성 방법을 지원합니다. 이 방법은 sticky 지시문으로 설정됩니다. (NGINX Open Source를 사용한 세션 지속성의 경우 에서 설명한 대로 hash 또는 ip_hash 지시문을 사용합니다.)

Sticky Cookie – NGINX Plus는 Upstream 그룹의 첫 번째 응답에 세션 쿠키를 추가하고 응답을 전송한 서버를 식별합니다. 클라이언트의 다음 요청에는 쿠키 값이 포함되며 NGINX Plus는 첫 번째 요청에 응답한 Upstream 서버로 요청을 라우팅합니다.

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    sticky cookie srv_id expires=1h domain=.example.com path=/;
}

이 예에서 srv_id 매개변수는 쿠키의 이름을 설정합니다. 선택적 expires 매개변수는 브라우저가 쿠키를 보관할 시간(여기서는 1시간)을 설정합니다. 선택적 domain 매개변수는 쿠키가 설정되는 도메인을 정의하고, 선택적 path 매개변수는 쿠키가 설정되는 경로를 정의합니다. 이것은 가장 간단한 세션 지속성 방법입니다.

Sticky Route – NGINX Plus는 첫 번째 요청을 수신할 때 클라이언트에 “route”를 할당합니다. 이후의 모든 요청은 server 지시문의 route 매개변수와 비교하여 요청이 Proxy되는 서버를 식별합니다. 경로 정보는 쿠키 또는 요청 URI에서 가져옵니다.

upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;
    sticky route $route_cookie $route_uri;
}

Sticky Learn 메서드 – NGINX Plus는 먼저 요청과 응답을 검사하여 세션 식별자를 찾습니다. 그런 다음 NGINX Plus는 어떤 업스트림 서버가 어떤 세션 식별자에 해당하는지 ” learns”합니다. 일반적으로 이러한 식별자는 HTTP 쿠키에 전달됩니다. 요청에 이미 “learned” 세션 식별자가 포함되어 있는 경우, NGINX Plus는 해당 서버로 요청을 전달합니다.

upstream backend {
   server backend1.example.com;
   server backend2.example.com;
   sticky learn
       create=$upstream_cookie_examplecookie
       lookup=$cookie_examplecookie
       zone=client_sessions:1m
       timeout=1h;
}

이 예제에서는 Upstream 서버 중 하나가 응답에 EXAMPLECOOKIE 쿠키를 설정하여 세션을 생성합니다.

필수적인 create 매개변수는 새 세션이 생성되는 방법을 나타내는 변수를 지정합니다. 이 예제에서는 Upstream 서버에서 전송한 EXAMPLECOOKIE 쿠키에서 새 세션이 생성됩니다.

필수적인 lookup 매개변수는 기존 세션을 검색하는 방법을 지정합니다. 이 예제에서는 클라이언트가 전송한 EXAMPLECOOKIE 쿠키에서 기존 세션을 검색합니다.

필수적인 zone 매개변수는 고정 세션에 대한 모든 정보가 보관되는 공유 메모리 Zone을 지정합니다. 이 예제에서 zone의 이름은 client_sessions이며 크기는 1MB입니다.

이는 클라이언트 측에 쿠키를 보관할 필요가 없고 모든 정보가 공유 메모리 Zone의 서버 측에 보관되므로 앞의 두 가지 방법보다 더 정교한 세션 지속성 방식입니다.

클러스터에 ” Sticky Learn” 방법을 사용하는 여러 NGINX 인스턴스가 있는 경우, 공유 메모리 Zone의 콘텐츠를 조건에 따라 동기화할 수 있습니다:

  • Zone의 이름이 같아야 합니다.
  • 각 인스턴스에서 zone_sync 기능이 구성됩니다.
  • sync 매개변수가 지정됩니다.
   sticky learn
       create=$upstream_cookie_examplecookie
       lookup=$cookie_examplecookie
       zone=client_sessions:1m
       timeout=1h
       sync;
}

7. 연결 수 제한

NGINX Plus를 사용하면 max_conns 매개변수로 최대 개수를 지정하여 Upstream 서버에 대한 활성화된 연결 수를 제한할 수 있습니다.

max_conns 제한에 도달하면 요청은 추가 처리를 위해 대기열에 배치되며, 대기열에 동시에 처리할 수 있는 최대 요청 수를 설정하는 queue 지시문도 포함되어야 합니다:

upstream backend {
    server backend1.example.com max_conns=3;
    server backend2.example.com;
    queue 100 timeout=70;
}

선택적 timeout 매개변수에 지정된 시간 제한 동안 대기열이 요청으로 가득 차거나 Upstream 서버를 선택할 수 없는 경우 클라이언트에 오류가 발생합니다.

다른 worker process에서 유휴 keepalive 연결이 열려 있는 경우 max_conns 제한은 무시됩니다. 따라서 메모리가 여러 Worker Process와 공유되는 구성에서는 서버에 대한 총 연결 수가 max_conns 값을 초과할 수 있습니다.

8. Health Check 구성

NGINX는 HTTP Upstream 서버를 지속적으로 테스트하여 장애가 발생한 서버를 피하고 복구된 서버를 Load Balancing 그룹에 정상적으로 추가할 수 있습니다.

9. 여러 Worker Process와 데이터 공유

upstream 블록에 zone 지시문이 포함되지 않은 경우 각 Worker Process는 서버 그룹 구성의 자체 복사본을 유지하고 자체 관련 카운터 집합을 유지합니다. 카운터에는 그룹 내 각 서버에 대한 현재 연결 수와 서버에 요청을 전달하려는 시도 실패 횟수가 포함됩니다. 따라서 서버 그룹 구성을 동적으로 수정할 수 없습니다.

zone 지시문이 upstream 블록에 포함되면, Upstream 그룹의 구성은 모든 Worker Process가 공유하는 메모리 Zone에 유지됩니다. 이 시나리오는 Worker Process가 그룹 구성의 동일한 복사본에 액세스하고 동일한 관련 카운터를 활용하므로 동적으로 구성할 수 있습니다.

zone 지시문은 Upstream 그룹의 Active Health Check동적 재구성을 위해 필수입니다. 그러나 이 지시문을 사용하면 Upstream 그룹의 다른 기능에서도 이점을 얻을 수 있습니다.

예를 들어 그룹 구성이 공유되지 않는 경우 각 Worker Process는 서버에 요청을 전달하려는 시도 실패에 대한 자체 카운터를 유지합니다(max_fails 매개변수로 설정). 이 경우 각 요청은 하나의 Worker Process에만 전달됩니다. 요청을 처리하도록 선택된 Worker Process가 요청을 서버로 전송하는 데 실패하면 다른 Worker Process는 해당 요청에 대해 아무것도 알지 못합니다. 일부 Worker Process는 서버를 사용할 수 없는 것으로 간주할 수 있지만 다른 Worker Process는 여전히 이 서버로 요청을 보낼 수 있습니다. 서버를 확실히 사용할 수 없는 것으로 간주하려면 fail_timeout 매개변수에 의해 설정된 기간 동안 실패한 시도 횟수가 max_fails에 Worker Process의 수를 곱한 수와 같아야 합니다. 반면, zone 지시문은 예상되는 동작을 보장합니다.

마찬가지로 Least Connections Load Balancing 방법은 적어도 부하가 적을 때는 zone 지시문이 없으면 예상대로 작동하지 않을 수 있습니다. 이 방법은 활성화된 연결 수가 가장 적은 서버로 요청을 전달합니다. 그룹 구성이 공유되지 않으면 각 Worker Process는 연결 수에 대해 자체 카운터를 사용하며 다른 Worker Process가 방금 요청을 보낸 것과 동일한 서버에 요청을 보낼 수 있습니다. 물론 요청 수를 늘려 이 효과를 줄일 수 있습니다. 부하가 높으면 요청이 Worker Process 간에 균등하게 분산되고 Least Connections 방법은 정상적으로 작동합니다.

9-1. Zone 크기 설정

사용 패턴은 매우 다양하기 때문에 이상적인 메모리 Zone 크기를 권장할 수는 없습니다. 필요한 메모리 양은 어떤 기능(세션 지속성, Health Check 또는 DNS 재확인 등)을 사용 설정하고 Upstream 서버를 어떻게 식별하는지에 따라 결정됩니다.

예를 들어 sticky_route 세션 지속성 메서드와 단일 Health Check을 사용하도록 설정하면 256KB Zone에 표시된 Upstream 서버 수에 대한 정보를 수용할 수 있습니다.

128개 서버(각각 IP 주소: 포트 쌍으로 정의됨)

88개 서버(각각 호스트명이 단일 IP 주소로 확인되는 호스트명: 포트 쌍으로 정의됨)

12개 서버(각각 호스트명이 여러 IP 주소로 확인되는 호스트명: 포트 쌍으로 정의됨)

10. DNS를 사용하여 HTTP Load Balancing 구성

서버 그룹의 구성은 DNS를 사용하여 런타임에 수정할 수 있습니다.

server 지시문에서 도메인 이름으로 식별되는 Upstream 그룹의 서버의 경우, NGINX Plus는 해당 DNS 레코드에서 IP 주소 목록의 변경 사항을 모니터링하고 재시작할 필요 없이 자동으로 변경 사항을 Upstream 그룹의 Load Balancing에 적용할 수 있습니다. 이 작업은 server 지시문에 대한 resolve 매개변수와 함께 http 블록에 resolver 지시문을 포함하면 됩니다.

http {
    resolver 10.0.0.1 valid=300s ipv6=off;
    resolver_timeout 10s;
    server {
        location / {
            proxy_pass http://backend;
        }
    }
    upstream backend {
        zone backend 32k;
        least_conn;
        # ...
        server backend1.example.com resolve;
        server backend2.example.com resolve;
    }
}

이 예제에서 server 지시문에 대한 resolve 매개변수는 NGINX Plus가 backend1.example.combackend2.example.com 도메인 이름을 주기적으로 IP 주소로 다시 확인하도록 지시합니다.

resolver 지시문은 NGINX Plus가 요청을 전송하는 DNS 서버의 IP 주소(여기서는 10.0.0.1)를 정의합니다. 기본적으로 NGINX Plus는 레코드의 TTL(Time-to-Live)에 지정된 주기로 DNS 레코드를 재확인하지만 valid 매개변수(이 예제에서는 300초 또는 5분)를 사용하여 TTL 값을 재정의할 수 있습니다.

선택 사항인 ipv6=off 매개변수를 사용하면 기본적으로 IPv4 및 IPv6 주소 모두 확인이 지원되지만 Load Balancing에 IPv4 주소만 사용된다는 의미입니다.

도메인 이름이 여러 IP 주소로 확인되는 경우 해당 주소는 Upstream 구성에 저장되고 Load Balancing됩니다. 이 예제에서는 Least Connections Load Balancing 방법에 따라 서버가 Load Balancing됩니다. 서버의 IP 주소 목록이 변경된 경우 NGINX Plus는 즉시 새 주소 집합에 대한 Load Balancing을 시작합니다.

11. Microsoft Exchange 서버의 Load Balancing

NGINX Plus R7 이상에서 NGINX Plus는 Microsoft Exchange 트래픽을 서버 또는 서버 그룹으로 Proxy하고 Load Balancing할 수 있습니다.

Microsoft Exchange 서버의 Load Balancing을 설정합니다.

1. location 블록에서 proxy_pass 지시문을 사용하여 Microsoft Exchange 서버의 Upstream 그룹에 대한 Proxy를 구성합니다.

location / {
    proxy_pass https://exchange;
    # ...
}

2. Microsoft Exchange 연결이 Upstream 서버로 전달되도록 하려면 Keepalive 연결과 마찬가지로 location 블록에서 proxy_http_version 지시문 값을 1.1로 설정하고 proxy_set_header 지시문을 Connection ""으로 설정합니다.

location / {
    # ...
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    # ...
}

3. http 블록에서, 1단계에서 proxy_pass 지시문으로 지정한 Upstream 그룹과 동일한 이름의 upstream 블록을 사용하여 Microsoft Exchange 서버의 Upstream 그룹을 구성합니다. 그런 다음 그룹의 서버가 NTLM 인증으로 요청을 수락할 수 있도록 ntlm 지시문을 지정합니다.

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        # ...
    }
}

4. Upstream 그룹에 Microsoft Exchange 서버를 추가하고 선택적으로 Load Balancing 방법을 지정합니다.

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        server exchange1.example.com;
        server exchange2.example.com;
        # ...
    }
}

11-1. 전체 NTLM 예제

http {
    # ...
    upstream exchange {
        zone exchange 64k;
        ntlm;
        server exchange1.example.com;
        server exchange2.example.com;
    }
    
    server {
        listen              443 ssl;
        ssl_certificate     /etc/nginx/ssl/company.com.crt;
        ssl_certificate_key /etc/nginx/ssl/company.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
       
        location / {
            proxy_pass         https://exchange;
            proxy_http_version 1.1;
            proxy_set_header   Connection "";
        }
    }
}

12. NGINX Plus API를 사용한 동적 구성

NGINX Plus를 사용하면 NGINX Plus API를 사용하여 Upstream 서버 그룹의 구성을 동적으로 수정할 수 있습니다. 구성 명령을 사용하여 그룹의 모든 서버 또는 특정 서버를 보고, 특정 서버의 매개변수를 수정하고, 서버를 추가 또는 제거할 수 있습니다.