
Proxy된 HTTP 리소스에 대한 액세스 제한
NGINX Plus 의 클라이언트 IP 주소 또는 기타 변수를 기반으로 연결, 요청 속도 또는 대역폭을 제한하여 Upstream 웹 및 애플리케이션 서버를 보호하세요.
이 문서에서는 연결에 대한 최대 요청 수 또는 서버에서 콘텐츠를 다운로드하는 최대 속도를 설정하는 방법에 대해 설명합니다.
목차
1. 소개
2. 연결 수 제한
3. 요청 속도 제한
3-1. 요청 속도 제한 테스트
3-2. 과도한 요청 처리
3-3. 과도한 요청 지연
3-4. 여러 공유 메모리 Zone의 콘텐츠 동기화하기
4. 대역폭 제한
4-1. 동적 대역폭 제어
1. 소개
NGINX 및 NGINX Plus를 사용하여 제한할 수 있습니다.
- Key 별 연결 수(예: IP Address 별)
- Key 별 요청 비율(1초 또는 1분 동안 처리할 수 있는 요청 수)
- 연결 다운로드 속도
Note: NAT 디바이스 뒤에서 IP 주소를 공유할 수 있으므로 IP 주소로 제한하는 것은 신중하게 사용해야 합니다.
2. 연결 수 제한
연결 수를 제한합니다.
1. limit_conn_zone
지시문을 사용하여 Key를 정의하고 공유 메모리 Zone의 매개변수를 설정합니다(Worker Processes는 이 Zone을 사용하여 Key 값에 대한 Counter를 공유하게 됩니다). 첫 번째 매개변수로 Key로 평가할 표현식을 지정합니다. 두 번째 매개변수 zone
에서 Zone의 이름과 크기를 지정합니다.
limit_conn_zone $binary_remote_addr zone=addr:10m;
2. limit_conn
지시문을 사용하여 location { }
, server { }
또는 http { }
컨텍스트 내에서 제한을 적용합니다. 첫 번째 매개변수로 공유 메모리 Zone의 이름을 지정하고 두 번째 매개변수로 Key 별 허용되는 연결 수를 지정합니다.
location /download/ {
limit_conn addr 1;
}
binary_remote_addr
변수가 Key로 사용되므로 연결 수는 IP 주소 기준으로 제한됩니다.
특정 서버의 연결 수를 제한하는 또 다른 방법은 $server_name
변수를 사용하는 것입니다.
http {
limit_conn_zone $server_name zone=servers:10m;
server {
limit_conn servers 1000;
}
}
3. 요청 속도 제한
속도 제한은 DDoS 공격을 방지하거나 동시에 너무 많은 요청으로 인해 Upstream 서버가 과부하되는 것을 방지하는 데 사용할 수 있습니다. 이 방법은 요청이 다양한 속도로 Bucket에 도착하고 고정된 속도로 Bucket을 떠나는 leaky bucket 알고리즘을 기반으로 합니다.
속도 제한을 사용하기 전에 “leaky bucket”의 전역 매개변수를 구성해야 합니다.
- Key – 한 클라이언트를 다른 클라이언트와 구별하는 데 사용되는 매개변수이며 일반적으로 변수입니다.
- 공유 메모리 Zone – 이러한 Key의 상태를 보관하는 Zone의 이름과 크기(“leaky bucket”)
- 속도 – 초당 요청(
r/s
) 또는 분당 요청(r/m
)으로 지정된 요청 속도 제한(“leaky bucket draining”). 분당 요청은 초당 한 건의 요청보다 적은 비율을 지정하는 데 사용됩니다.
이러한 매개변수는 limit_req_zone
지시문으로 설정합니다. 이 지시문은 http { }
Level에서 정의되며, 이러한 접근 방식을 통해 서로 다른 Zone과 요청 오버플로 매개변수를 서로 다른 컨텍스트에 적용할 수 있습니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}
이 구성을 사용하면 10MB 크기의 공유 메모리 Zone 1
이 생성됩니다. 이 영역은 $binary_remote_addr
변수로 설정된 클라이언트 IP 주소의 상태를 유지합니다. 클라이언트의 IP 주소도 보관하는 $remote_addr
에 비해 $binary_remote_addr
에는 더 짧은 IP 주소의 Binary 표현이 보관된다는 점에 유의하세요.
공유 메모리 Zone의 최적의 크기는 다음 데이터를 사용하여 계산할 수 있습니다. $binary_remote_addr
값의 크기는 IPv4 주소의 경우 4Byte이며, 저장된 상태는 64Bit 플랫폼에서 128Byte를 차지합니다. 따라서 약 16,000개의 IP 주소에 대한 상태 정보는 1MB의 영역을 차지합니다.
새 항목을 추가해야 할 때 저장 공간이 모두 소진되면 NGINX는 가장 오래된 항목을 제거합니다. 확보된 공간이 여전히 새 레코드를 수용하기에 충분하지 않으면 NGINX는 상태 코드 503 Service Unavailable
을 반환합니다. 상태 코드는 limit_req_status
지시문으로 재정의할 수 있습니다.
Zone이 설정되면 server { }
, location { }
또는 http { }
컨텍스트에 대해 지정된 limit_req
를 사용하여 NGINX 구성의 어느 곳에서나 요청 제한을 사용할 수 있습니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
}
}
}
이 구성을 사용하면 NGINX는 /search/
위치 내에서 초당 1개 이하의 요청만 처리합니다. 이러한 요청의 처리는 전체 속도가 지정된 속도보다 크지 않도록 지연됩니다. 요청 수가 지정된 속도를 초과하는 경우 NGINX는 ‘Bucket'(공유 메모리 Zone 1
)이 가득 찰 때까지 해당 요청의 처리를 지연합니다. 가득 찬 Bucket에 도착한 요청에 대해 NGINX는 503 Service Unavailable
오류(limit_req_status
로 재정의하지 않은 경우)로 응답합니다.
3-1. 요청 속도 제한 테스트
실제 속도 제한을 구성하기 전에 요청 처리 속도를 제한하지 않는 “dry run” 모드를 사용해 볼 수 있습니다. 그러나 이러한 과도한 요청은 여전히 공유 메모리 Zone에 기록되고 기록됩니다. “dry run” 모드는 limit_req_dry_run
지시문을 사용하여 활성화할 수 있습니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one;
limit_req_dry_run on;
}
}
}
정의된 속도 제한을 초과하는 모든 요청은 ‘dry run’ 표시와 함께 기록됩니다.
2019/09/03 10:28:45 [error] 142#142: *13246 limiting requests, dry run, excess: 1.000 by zone "one", client: 172.19.0.1, server: www.example.com, request: "GET / HTTP/1.0", host: "www.example.com:80"
3-2. 과도한 요청 처리
요청은 limit_req_zone
지시문에 정의된 비율에 맞게 제한됩니다. 요청 수가 지정된 속도를 초과하여 공유 메모리 Zone이 가득 차면 NGINX는 오류로 응답합니다. 트래픽이 폭주하는 경향이 있으므로 트래픽이 폭주하는 동안 클라이언트 요청에 대한 응답으로 오류를 반환하는 것은 최선의 경우가 아닙니다.
NGINX에서 이러한 과도한 요청은 버퍼링되어 처리될 수 있습니다. limit_req
지시문의 burst
매개변수는 지정된 속도로 처리되기를 기다리는 과도한 요청의 최대 수를 설정합니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5;
}
}
}
이 구성을 사용하면 요청 속도가 초당 1
건의 요청을 초과하는 경우 초과 요청이 1
번 영역에 배치됩니다. Zone이 가득 차면 초과 요청이 Queue(burst
)되며, 이 Queue의 크기는 5개의 요청입니다. 대기열의 요청 처리는 전체 속도가 지정된 것보다 크지 않도록 지연됩니다. Burst 제한을 초과하는 요청은 503
오류와 함께 거부됩니다.
트래픽 폭주 시 요청 지연을 원하지 않는 경우, nodelay
매개변수를 추가하세요.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5 nodelay;
}
}
}
이 구성을 사용하면 burst
한도 내에서 초과 요청은 지정된 rate
에 관계없이 즉시 처리되며, Burst 한도를 초과하는 요청은 503
오류와 함께 거부됩니다.
3-3. 과도한 요청 지연
과도한 요청을 처리하는 또 다른 방법은 이러한 요청을 지체 없이 일정한 수만큼 처리한 다음 과도한 요청이 거부되는 시점까지 속도 제한을 적용하는 것입니다.
이는 delay
및 burst
매개변수를 사용하여 달성할 수 있습니다. delay
매개변수는 정의된 전송률 제한을 준수하기 위해 과도한 요청이 지연되는 지점을 정의합니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
#...
location /search/ {
limit_req zone=one burst=5 delay=3;
}
}
}
이 구성을 사용하면 처음 3개의 요청(delay
)은 지체 없이 통과되고, 다음 2개의 요청(burst
– delay
)은 전체 비율이 지정한 것보다 크지 않도록 지연되며, 총 Burst 크기가 초과되었으므로 더 이상의 초과 요청은 거부되고, 후속 요청은 지연됩니다.
3-4. 여러 공유 메모리 Zone의 콘텐츠 동기화하기
여러 개의 NGINX 인스턴스가 있는 컴퓨터 클러스터가 있고 이러한 인스턴스가 limit_req
메서드를 사용하는 경우, 다음과 같은 조건에서 공유 메모리 Zone의 콘텐츠를 동기화할 수 있습니다.
각 인스턴스에 대해 zone_sync
기능이 구성됩니다.
각 인스턴스에 대해 limit_req_zone
지시문으로 설정된 공유 메모리 Zone은 동일한 이름을 갖습니다.
limit_req_zone
지시문의 sync
매개변수는 각 인스턴스에 대해 지정됩니다.
http {
#...
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s sync;
}
4. 대역폭 제한
연결 별 대역폭을 제한하려면 limit_rate
지시문을 사용합니다.
location /download/ {
limit_rate 50k;
}
이 설정을 사용하면 클라이언트가 단일 연결을 통해 초당 최대 50
KB의 속도로 콘텐츠를 다운로드할 수 있습니다. 그러나 클라이언트는 여러 연결을 열 수 있습니다. 따라서 지정된 값보다 빠른 다운로드 속도를 방지하는 것이 목표라면 연결 수 또한 제한해야 합니다. 예를 들어, IP 주소당 하나의 연결(위에 지정된 공유 메모리 Zone이 사용되는 경우):
location /download/ {
limit_conn addr 1;
limit_rate 50k;
}
클라이언트가 일정량의 데이터를 다운로드한 후에만 제한을 적용하려면 limit_rate_after
지시문을 사용합니다. 클라이언트가 일정량의 데이터(예: 파일 헤더 – 영화 색인)를 빠르게 다운로드할 수 있도록 허용하고 나머지 데이터의 다운로드 속도를 제한하는 것이 합리적일 수 있습니다(사용자가 다운로드가 아닌 영화를 시청하도록 하기 위해).
limit_rate_after 500k;
limit_rate 20k;
다음 예제는 연결 수와 대역폭을 제한하기 위한 조합 구성을 보여줍니다. 허용되는 최대 연결 수는 클라이언트 주소당 5개의 연결로 설정되어 있으며, 최신 브라우저는 일반적으로 한 번에 최대 3개의 연결을 열기 때문에 대부분의 일반적인 경우에 적합합니다. 한편 다운로드를 제공하는 위치는 하나의 연결만 허용합니다.
http {
limit_conn_zone $binary_remote_address zone=addr:10m
server {
root /www/data;
limit_conn addr 5;
location / {
}
location /download/ {
limit_conn addr 1;
limit_rate_after 1m;
limit_rate 50k;
}
}
}
4-1. 동적 대역폭 제어
limit_rate
값은 변수로 지정할 수도 있는데, 이를 통해 최신 브라우저에 더 높은 대역폭 제한을 허용하는 등 동적 대역폭 사용 사례를 사용할 수 있습니다.
map $ssl_protocol $response_rate {
"TLSv1.1" 10k;
"TLSv1.2" 100k;
"TLSv1.3" 1000k;
}
server {
listen 443 ssl;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
location / {
limit_rate $response_rate; # Limit bandwidth based on TLS version
limit_rate_after 512; # Apply limit after headers have been sent
proxy_pass http://my_backend;
}
}