이번 시간에는 Nginx를 활용한 트래픽 제어를 다룰 예정이다.

전송 대역폭 제한

1
2
3
4
5
location /download/ {
    limit_rate_after 10m;
    limit_rate 1m;
    ...
}

위 설정은 서버 리소스의 부하를 막기 위해, 사용자당 다운로드 대역폭을 제한하는 상황에 대한 예시이다. /download/ 하위 uri에 대해, 누적 전송량이 10메가바이트를 초과할 경우, 초당 1mb로 대역폭을 제한한다.

연결 제한

1
2
3
4
5
6
7
8
9
10
11
http {
    limit_conn_zone $binary_remote_addr zone=limit_by_addr:10m;
    limit_conn_status 429;

    # ...
    server {
        # ...
        limit_conn limit_by_addr 40;
        # ...
    }
}

위 설정은 사용자 IP 주소를 통해 연결 수를 제한하는 예시이다. limit_conn_zone 구문을 통해 limit_by_addr라는 공유 메모리 영역을 생성하며 (10mb 용량), 바이너리 형태의 사용자 IP 주소($binary_remote_addr)를 사전 정의된 키로 사용한다.

limit_conn 구문은 limit_conn_zone으로 선언한 공유 메모리 영역과 허용 연결 수를 파라미터로 받는다. 해당 구문을 통해 지정된 연결 수를 초과할 경우, limit_conn_status를 통해 설정한 HTTP Status Code를 제공한다.

limit_conn, limit_conn_status 구문은 http, server, location 에서 사용할 수 있다.

요청 빈도 제한

1
2
3
4
5
6
7
8
9
10
11
http {
    limit_req_zone $binary_remote_addr zone=limit_by_addr:10m rate=3r/s;
    limit_req_status 429;

    # ...
    server {
        # ...
        limit_req zone=limit_by_addr;
        # ...
    }
}

limit_req_zone은 앞서 설명한것과 동일하게 공유 메모리 영역을 생성한다. 이때 rate 파라미터를 통해 요청 빈도를 제한할 수 있으며, 위 설정의 경우 동일한 IP에 대해서 초당 요청 수를 3개로 제한한다(rate=3r/s).
limit_req구문은 zone 파라미터를 통해 어떤 공유 메모리 영역을 참고해 요청 빈도를 제한할지 결정한다.

추가적인 빈도 제한

limit_req 구문은 zone과 별개로, 추가적인 파라미터를 통해 요청 빈도를 제한할 수 있다.

1
2
3
4
5
server {
    location / {
        limit_req zone=limit_by_addr burst=12 delay=9;
    }
}

간혹 한번에 많은 요청을 전송할 수 일정 시간 동안 요청 빈도를 줄이는 경우가 있다(한번에 몰아서 요청을 보내는 케이스).

burst 파라미터를 통해 빈도가 지정된 값보다 낮으면 허용하도록 설정할 수 있다. 단 delay 값을 초과한 요청에 대해서는 지정된 rate에 맞춰 지연 처리를 수행한다.

클라이언트 분기 (A/B 테스트)

보통 다양한 버전에 대한 사용자의 반응을 모니터링 하기 위해, 두 개 이상의 파일이나 서비스로 사용자를 분기하는 경우가 있다.

1
2
3
4
5
6
7
split_clients "${remote_addr}" $variant {
    20.0%   "backend_v2";
    *       "backend_v1";
}
location / {
    proxy_pass http://$variant;
}

위 설정은 split_clients 모듈을 통해 비율에 따라 서로 다른 접속 정보(업스트림 풀)를 제공한다. 위 요청의 경우 $variant 변수는 20%의 사용자에게만 backend_v2가 할당되고, 나머지 사용자에게는 backend_v1가 할당된다.

다음 설정을 통해 두 가지 버전의 정적 웹사이트로 사용자 요청을 분기시킬 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http {
    split_clients "${remote_addr}" $site_root_dir {
        33.3%       "/var/www/site_v2/";
        *           "/var/www/site_v1/";
    }

    server {
        listen 80 default_server;
        root $site_root_dir;
        location / {
            index index.html;
        }
    }
}

마치며

본 포스팅에 설명된 내용 외에도 트래픽 제어와 관련된 다양한 기능이 존재한다. 또한 연결 및 요청 빈도에 대한 제한 설정 시 Dry run 기능을 통해 모의 테스트를 진행할 수 있다.

최대한 다양한 기능을 활용하여, 더 나은 서비스 제공을 위한 고민과 다양한 시도를 해보는것이 좋을듯 하다.