[Nginx] 03. 트래픽 관리

Date:     Updated:

카테고리:

태그:


01. A/B 테스트 (A/B Testing)


# split_clients 모듈을 사용하여 클라이언트의 일부를 다른 업스트림 풀로 라우팅함
split_clients "${remote_addr}AAA" $variant {
  20.0% "backendv2";
  * "backendv1";
}

A/B 테스트 기능은 웹 트래픽을 여러 버전의 애플리케이션이나 서비스로 분할하여, 각각의 성능과 사용자 반응을 비교할 수 있도록 지원하는 기능이다. 이를 통해 특정 웹 페이지, 기능, 또는 서버 설정에 대해 실제 사용자 데이터를 기반으로 최적의 선택을 할 수 있다.

이 설정은 클라이언트 IP 주소를 해싱하고 제공된 비율에 따라 변수를 매핑한다. AAA는 여러 변수를 포함할 수 있는 문자열을 나타내며, 클라이언트의 IP 주소를 기반으로 트래픽의 20%를 backendv2로, 나머지 80%를 backendv1으로 분배한다.

# backendv1과 backendv2는 업스트림 서버 풀을 나타내며, proxy_pass 지시어와 함께 사용
location / {
    proxy_pass http://$variant;
}

이렇게 하면 트래픽이 두 개의 서로 다른 애플리케이션 서버 풀 간에 나뉜다.

# 정적 사이트 버전을 나누는 예시도 가능하다.
http {
    split_clients "${remote_addr}" $site_root_folder {
        33.3% "/var/www/sitev2/";
        * "/var/www/sitev1/";
    }
    server {
        listen 80;
        root $site_root_folder;
        location / {
            index index.html;
        }
    }
}

이 A/B 테스트 방식은 마케팅 또는 프런트엔드 기능 테스트에 유용하며, 점진적으로 새로운 버전으로 트래픽을 전환하는 카나리아 배포나 블루-그린 배포 방식에서도 활용된다.



02. GeoIP 모듈/데이터베이스 사용


NGINX에서 클라이언트의 실제 위치 정보를 활용하여 로그에 기록하거나 요청을 프록시하거나 라우팅하려면 GeoIP 데이터베이스와 관련 변수를 활성화해야한다.

# RHEL/CentOS NGINX Open Source:
yum install nginx-module-geoip

# RHEL/CentOS NGINX Plus:
apt-get install nginx-module-geoip
# Debian/Ubuntu NGINX Open Source:
apt-get install nginx-module-geoip

# Debian/Ubuntu NGINX Plus:
apt-get install nginx-plus-module-geoip
# GeoIP 국가 및 도시 데이터베이스를 다운로드하고 압축 해제
mkdir /etc/nginx/geoip
cd /etc/nginx/geoip
wget "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"
gunzip GeoIP.dat.gz
wget "http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz"
gunzip GeoLiteCity.dat.gz
# NGINX GeoIP 모듈을 사용하여 클라이언트 IP 주소를 기반으로 내장 변수를 노출할 수 있다.

# `load_module` 지시는 파일 시스템 상의 경로에서 모듈을 동적으로 로드
load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {

    # `geoip_country` 지시는 IP 주소를 국가 코드에 매핑하는 데이터베이스 파일인 `GeoIP.dat`의 경로를 가져오며, 이는 http 컨텍스트에서만 유효함
    geoip_country /etc/nginx/geoip/GeoIP.dat;
    geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
    # ...
}
  • geoip_country 지시어는 클라이언트의 원산 국가를 구분할 수 있게 하는 변수를 활성화한다.

    1) $geoip_country_code : 두 글자의 국가 코드를 반환

    2) $geoip_country_code3 : 세 글자의 국가 코드를 반환

    3) $geoip_country_name : 국가의 전체 이름을 반환

  • geoip_city 지시어는 geoip_country 지시어의 변수와 기능은 같지만, 이름이 다르다.

    1) $geoip_city_country_code

    2) $geoip_city_country_code3

    3) $geoip_city_country_name

GeoIP 모듈을 사용하면 클라이언트의 IP 주소를 기반으로 다양한 변수를 생성할 수 있습니다. 예를 들어, 국가 코드를 반환하는 $geoip_country_code와 같은 변수를 통해 클라이언트의 위치 정보를 로그에 기록하거나 애플리케이션에 전달할 수 있다.



03. 국가별 접근 제한


# 이 매핑을 통해 US(미국)에서의 접근은 $country_access 변수를 0으로 설정하고, 다른 국가는 1로 설정한다.

load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {
    map $geoip_country_code $country_access {
        "US" 0; 
        default 1;
    }
    # ...
}
# 서버 블록 내에서 if문을 사용하여 미국 이외의 국가에서의 접근을 차단

server {
    if ($country_access = '1') {
        return 403;
    }
    # ...
}

이 예시는 특정 국가에서만 접근을 허용하는 간단한 방법을 보여준다. GeoIP 모듈의 변수를 사용하여 다양한 국가별로 접근을 허용하거나 차단할 수 있다.



04. 실제 사용자 IP 찾기


해당 기능은 NGINX 서버 앞에 프록시가 있을 때 사용하며, 실제 사용자 IP 주소를 확인한다.

# geoip_proxy 지시어와 geoip_proxy_recursive 지시어를 사용하여 프록시 IP 범위를 정의하고, 실제 사용자 IP 주소를 찾아낸다.

load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so";
http {
    geoip_country /etc/nginx/geoip/GeoIP.dat;
    geoip_city /etc/nginx/geoip/GeoLiteCity.dat;

    # geoip_proxy: 지정된 CIDR 범위에 있는 프록시 서버의 IP 주소를 정의하고, X-Forwarded-For 헤더에서 클라이언트 IP를 찾는다.
    geoip_proxy 10.0.16.0/26;
    # X-Forwarded-For 헤더를 통해 마지막으로 알려진 클라이언트 IP를 재귀적으로 검색하도록 지시한다.
    geoip_proxy_recursive on;
    # ...
}

프록시가 NGINX 앞에 있을 때 NGINX는 프록시의 IP 주소를 가져오게 되므로, geoip_proxy 지시어를 사용해 해당 프록시 범위에서 연결이 열리면 X-Forwarded-For 헤더를 참조해 원본 클라이언트 IP를 얻을 수 있다.

여러 프록시가 있을 경우 geoip_proxy_recursive를 사용해 원본 클라이언트 IP를 재귀적으로 탐색할 수 있습니다.

이 설정은 Amazon Web Services Elastic Load Balancing (AWS ELB), Google의 로드 밸런서, Microsoft Azure의 로드 밸런서 등과 함께 사용할 때 유용하다.



05. 연결 제한하기


클라이언트의 IP 주소와 같은 미리 정의된 키를 기준으로 연결 수를 제한할 수 있다.

# 공유 메모리 영역을 만들어 연결 메트릭을 저장하고, limit_conn 지시어를 사용하여 열린 연결을 제한한다.

http {

    # 클라이언트 IP 주소(이진 형식)를 기반으로 10MB 크기의 공유 메모리 영역을 생성
    limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m;

    # 제한이 초과된 경우 HTTP 상태 코드 429(요청이 많음) 반환
    limit_conn_status 429;
    # ...
    
    server {
        # ...

        # limitbyaddr 메모리 영역에 대해 최대 40개의 연결 허용.
        limit_conn limitbyaddr 40;
        # ...
    }
}

이 설정은 자원을 공정하게 나누고 남용을 방지하는 데 유용하다. 그러나 NAT(Network Address Translation) 뒤에 있는 사용자들이 같은 IP를 사용할 경우, IP 기반 제한은 해당 그룹 전체에 영향을 미칠 수 있다. 따라서 세션 쿠키와 같은 애플리케이션 수준의 변수를 사용하는 것이 더 나을 수 있다.

limit_conn_status의 기본값은 503이지만, 서비스는 정상적이므로 400대 에러 코드인 429를 사용하는 것이 더 적절하다.

테스트 시에는 limit_req_dry_run을 활성화하여 실제 트래픽 로그를 분석하고 설정을 조정할 수 있다.



06. 요청 속도 제한


클라이언트 IP 주소와 같은 미리 정의된 키를 기준으로 요청 속도를 제한할 수 있다.

# rate-limiting 모듈을 사용하여 요청 속도를 제한한다.

http {

    # 클라이언트 IP 주소를 기반으로 10MB 크기의 공유 메모리 영역을 생성하고, 초당 3개의 요청만 허용
    limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=3r/s;

    # 요청이 제한을 초과하면 429 HTTP 상태 코드(요청이 많음)를 반환
    limit_req_status 429;
    # ...
    
    server {
        # ...
        limit_req zone=limitbyaddr;
        # ...
    }
}
server {
    location / {

        # limit_req 지시어에 선택적 키워드 인수를 추가하여 두 단계 속도 제한을 설정할 수 있다.
        # burst: 클라이언트가 제한을 초과해도 즉시 거부되지 않도록 최대 12개의 추가 요청 허용.
        # delay: 초기 9개의 요청은 지연 없이 처리되며, 이후의 요청은 속도 제한에 맞춰 지연됨.
        limit_req zone=limitbyaddr burst=12 delay=9;
    }
}

rate-limiting 모듈은 악의적인 대량 요청으로부터 서버를 보호하면서도 정상 사용자에게는 양질의 서비스를 제공한다.

보안 목적으로 로그인 페이지에 엄격한 제한을 두거나, 모든 요청에 대해 제한을 설정해 악의적인 사용자들이 자원을 낭비하지 못하게 할 수 있다.

테스트를 위해 limit_req_dry_run을 사용해 실제 트래픽 로그를 분석한 후 설정을 조정할 수 있다.



07. 대역폭 제한


다운로드 시 클라이언트별로 다운로드 대역폭을 제한할 수 있다.

# limit_rate와 limit_rate_after 지시어를 사용하여 클라이언트에 대한 응답 대역폭을 제한

location /download/ {
    limit_rate_after 10m;
    limit_rate 1m;
}

이 설정은 /download/로 시작하는 URI에 대해, 10MB를 전송한 후 응답 속도가 초당 1MB로 제한됨을 지정한다. 대역폭 제한은 연결당 적용되므로 필요한 경우 연결 제한과 함께 사용하는 것이 좋다.

limit_rate_after는 특정 데이터 양이 전송된 후 대역폭을 제한하며, limit_rate는 초당 전송 속도를 제한한다.

NGINX 카테고리 내 다른 글 보러가기

댓글 남기기