NGINX를 사용하면 HTTP Request의 요청량을 조절할 수 있다.
Rate Limiting with NGINX여기에 그 내용이 잘 설명돼 있다.
이 기능을 사용하면 http 리퀘스트의 요청량을 조절할 수 있다. brute‑force password‑guessing attacks(무차별 대입 공격)을 막는데 주로 활용할 수 있다. 실 이용자에 한해서만 http 리퀘스트 요청을 허용함으로써 DDoS attacks도 막을 수 있다.
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
# 일반 HTTP API용
location / {
limit_req zone=mylimit;
proxy_pass http://wsbackend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
limit_req_zone directive는 보통 http block에 정의된다. 여기는 세가지 파라미터가 존재한다.
key 제한이 적용될 요청을 정의하는 것이다. $binary_remote_addr이건 클라이언트의 ip 주소를 담고 있다. 즉, 클라이언트 ip마다 rate limit을 계산하고 차단한다는 것이다.
Zone은 공유 메모리 영역으로, 각 ip의 상태와 이 ip들이 url에 얼마나 자주 접근했는지를 저장한다.
Rate는 리퀘스트 rate의 최대치를 설정한다. 위 설정은 1초에 10번을 허용한다는 뜻이다.(더 정확히는 0.1초마다 1번의 요청을 허용한다는 뜻이다. burst 설정을 안해주면, 100ms 안에 요청이 2번 들어오면 거절된다)
지금 단계에서 고려할만한 이슈는 아니지만 NGINX는 트래픽 급증에 대비할 수 있는 burst 기능을 제공한다.
앞서 말했듯, NGINX는 rate=10r/s 를 설정하면. 0.1초마다 1건의 리퀘스트를 허용한다. 0.1초에 2~3개의 리퀘스트가 들어오면 503을 코드를 반환한다.
이때 추가로 들어온 요청을 buffer에 담아놓고 추후에 처리할 수 있다.
대신 이 방법은 로그인이나 결제같은 경우는 넣지 않고, 다른 api에 경우 추가해주는 게 좋아보인다.
이런식으로 설정해줄 수 있다.
그런데 지금은 이런 burst 설정을 해줄 필요는 없어 보인다.
이외에도 n개까지는 a의 속도로 처리, 그 이후로는 b 속도로 처리하는 기능과 특정 ip를 제외하는 기능들이 있다.
지금 우리 아키텍처에서는 burst같은 설정이 불필요해보인다.
각자 디바이스에서 백엔드 서버로 api 요청을 보내는 구조라서, 초당 10번 이상의 api 요청이 올 일은 거의 없기 때문이다.
rate limiting의 구조는 login이나 결제처럼 어뷰징을 강하게 막아야 하는 경우 초당 1번, 일반적인 api의 경우 초당 10번을 허용하는 느슨한 방식을 활용하기로 했다.
이걸 어떻게 테스트하면 좋을지... 찾아보다가
for i in {1..3}; do
curl -i -X GET http://localhost:80/api/v1/user/get-profile -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmbmVsMTIzIiwiZXhwIjoxNzM0NjA2OTEzLCJpYXQiOjE3MzQ1ODg5MTN9.knI17HxD7Euy0jKTGwLOnCrl8lEJ8i9ZcjPT0yj5Np0"
echo "Request $i completed"
done
bash로 이렇게 스크립트를 짜서 요청을 3번 보낸다.(우선 초당 1번만 허용하게 했다)
503에러가 뜨는 걸 확인할 수 있다.
에러 로그에도 잘 잡힌다.
다만, 지금은 503 에러로 가기 때문에 이를 429 응답(TooManyRequest)로 변경해주자.
테스트 해보면 429 코드로 응답된다.