Nginx로 API 요청 횟수 제한 설정하기

June·2024년 11월 12일
0

서버가 과도한 요청에 의해 과부하되는 것을 방지하기 위해 Nginx로 요청 횟수 제한을 설정하는 방법을 소개합니다. 이 방법을 통해 특정 경로(/api/)에 대해 요청을 제한하고, 서버의 안정성을 유지할 수 있습니다. Nginx의 limit_req 모듈을 사용하면 쉽게 구현할 수 있습니다.

1. Nginx 설정 파일 수정

먼저, 요청 속도를 제한하기 위해 Nginx 설정 파일을 수정해야 합니다. 기본적으로 요청 속도 제한을 위한 limit_req_zone을 설정하고, 특정 경로(/api/)에 대해 limit_req를 적용합니다.

1.1 limit_req_zone 설정

limit_req_zone은 요청 속도를 추적하기 위한 메모리 영역(zone)을 정의합니다. 이 설정은 http 블록에 추가되어야 합니다.

  • Nginx 설정 파일로 이동합니다.
cd /etc/nginx/
sudo vim nginx.conf
  • limit_req_zone 을 설정합니다.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {
    # 요청 속도 제한을 위한 zone 정의 (1초에 100번 요청)
		limit_req_zone $binary_remote_addr zone=api_limit:5m rate=100r/s;

    # 다른 설정들...
}

limit_req_zone:

  • api_limit: 요청을 추적할 메모리 영역의 이름입니다.
  • zone=api_limit:5m: 이 메모리 영역은 5MB의 크기를 가집니다.
  • rate=100r/s: 1초에 최대 100개의 요청을 허용합니다.
  • $binary_remote_addr: 클라이언트의 IP 주소를 기준으로 요청을 추적합니다.

1.2 limit_req 설정

이제 server 또는 location 블록 내에서 실제로 요청 제한을 적용합니다. 예를 들어 /api/ 경로에 대해 요청 횟수를 제한하고, 초과된 요청은 거부하도록 설정할 수 있습니다.

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain/privkey.pem;

    # API 요청을 Spring 백엔드로 프록시
    location /api/ {
		    # 초과 요청을 200개까지 허용, 초과는 즉시 거부
        limit_req zone=api_limit burst=200 nodelay;  

        proxy_pass http://localhost:8080;  # Spring 서버로 요청을 프록시
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  • limit_req zone=api_limit: 앞에서 정의한 api_limit 메모리 영역을 사용하여 요청 제한을 적용합니다.
  • burst=200: burst*는 초과할 수 있는 요청 수를 설정합니다. 예를 들어, 1초에 100번 요청을 허용하는데 200개**까지는 일시적으로 허용합니다.
  • nodelay: 초과된 요청을 즉시 거부하도록 설정합니다. 즉, 200번을 초과한 요청은 지연 없이 바로 503 오류가 발생합니다.

2. 설정 적용

설정을 완료한 후에는 Nginx를 재로드하여 변경사항을 적용해야 합니다.

sudo nginx -s reload

3. 설정 확인

설정이 제대로 적용되었는지 확인하려면 ab (Apache Benchmark) 도구를 사용하여 요청을 보내고, HTTP 503 오류가 발생하는지 확인할 수 있습니다.

ab -n 200 -c 200 https://matal.kro.kr/api/store/1
  • n 200: 총 201개의 요청을 보냅니다.
  • c 200: 한 번에 201개의 요청을 동시 실행합니다.

이 명령을 실행한 후 503 Service Unavailable 오류가 발생하면, 요청 제한이 제대로 작동하고 있다는 것을 확인할 수 있습니다.

4. 설정 확인 테스트 결과

nodelaydelay는 요청 초과 시 처리하는 방식에서 중요한 차이를 보입니다.

  • nodelay: 초과 요청을 즉시 503 오류로 처리합니다. 이 방식은 서버 부하를 바로 줄일 수 있지만, 사용자에게 갑작스러운 오류를 경험하게 할 수 있습니다.
  • delay: 초과된 요청을 대기열에 쌓아 두고 처리합니다. 이 방식은 사용자에게 더 부드러운 경험을 제공하지만, 요청이 대기열에 쌓이는 동안 응답 시간이 지연될 수 있습니다.

1번째 테스트

ab -n 200 -c 200 https://matal.kro.kr/api/store/1
  • nodelay인 경우 - 실패 횟수 0회

  • delay = 10인 경우 - 0회

2번째 테스트

ab -n 300 -c 300 https://matal.kro.kr/api/store/1
  • nodelay인 경우 - 실패 횟수 27회

  • delay = 10인 경우 - 25회

💡 Apache Benchmark 도구를 사용한 테스트가 정확하다고 할 수 없습니다. 네트워크가 어떻게 구성되어 있고 요청이 어떤 네트워크를 거쳐 들어오는지 모르기 때문에 매 테스트마다 실패 요청이 다릅니다. 감안하고 봐주세요!!

5. 문제 해결

  • 만약 503 오류가 자주 발생하는 경우, burst 값이나 rate를 조정하여 서버 부하를 관리할 수 있습니다.
  • nodelay 대신 delay를 사용하여 초과 요청이 대기열에 쌓이도록 할 수도 있습니다.

결론

Nginx의 limit_req 모듈을 사용하면 특정 API 경로에 대해 요청 횟수를 제한할 수 있습니다. 이 설정을 통해 API 서버의 부하를 관리하고, 비정상적인 트래픽을 제한하여 시스템의 안정성을 확보할 수 있습니다.

profile
😊

0개의 댓글