•
네트워크 시스템 상에서 처리율 제한 장치는 클라이언트 또는 서비스가 보내는 트래픽의 처리율을 제어하기 위한 장치다.
•
즉, API 요청 횟수가 제한 장치에 정의된 임계치를 넘어서면 추가로 도달한 모든 호출은 처리가 중단된다. 다음은 몇 가지 사례다.
◦
사용자는 초당 2회 이상 글을 작성할 수 없다.
◦
같은 IP 주소로는 하루에 10개 이상의 동일한 요청이 불가능하다.
◦
같은 디바이스로는 주당 5회 이상 리워드를 요청할 수 없다.
•
이런 처리율 제한 장치를 두었을 때, 장점은 다음과 같다.
◦
Dos 공격에 의한 자원 고갈 방지
◦
비용절감
◦
서버 과부하
1단계 문제 이해 및 설계 범위 설정
•
면접관이 처리율 제한 장치를 설계해야 한다고 했을 때, 우리는 각각 장, 단점을 가지는 다양한 알고리즘들을 고려할 수 있다.
•
이 역시, 장, 단점에 따라 적절히 결정할 수 있도록 요구사항을 분명하게 이해하는 과정이 필요하다.
대표적인 요구사항
•
설정된 처리율을 초과하는 요청을 제한할 수 있어야 한다.
•
HTTP 응답시간에 나쁜 영향을 주어서는 안 된다.
•
가능한 적은 메모리를 사용해야 한다.
•
분산형 처리율 제한이 가능해야 한다.
•
예외 처리를 적절히 해야 한다.
•
제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어서는 안 된다.
2단계 개략적 설계안 제시 및 동의 구하기
•
기본적인 클라이언트-서버 통신 모델에 적용시킨다고 가정하자.
처리율 제한 장치는 어디에 둘 것인가?
•
API 서버에 둘 수도 있고 미들웨어로 만들어 API 서버로 가능 요청을 통제하게끔 할 수 있다.
•
클라우드 마이크로서비스인 경우, 처리율 제한 장치는 보통 API 게이트웨이라 불리는 컴포넌트에 구현된다.
처리율 제한 알고리즘
•
토큰 버킷 알고리즘
◦
정의
▪
지정된 용량을 가지는 컨테이너로 이 버킷에는 사전 설정된 양의 토큰이 주기적으로 채워진다. 그리고 각 요청은 처리될 때마다 하나의 토큰을 사용한다.
▪
요청이 도착하면 먼저 버킷에 충분한 토큰이 있는지 검사하게 된다.
◦
장점
▪
구현이 쉽다.
▪
메모리 사용 측면에서도 효율적이다.
▪
짧은 시간에 집중되는 트래픽도 처리 가능하다. 버킷에 남은 토큰이 있기만 하면 요청은 시스템에 전달될 것이다.
◦
단점
▪
이 알고리즘은 버킷 크기와 토큰 공급률이라는 두 개 인자를 가지고 있는데, 이 값을 적절하게 튜닝하는 것은 까다로운 일이 된다.
•
누출 버킷 알고리즘
◦
정의
▪
토큰 버킷 알고리즘과 유사하지만 요청 처리율이 고정되어 있다는 점이 다르다.
▪
이는 보통 큐로 구현하며 동작 원리는 다음과 같다.
•
요청이 도착하면 큐가 가득 차 있는지 보며, 빈자리가 있는 경우, 큐에 요청을 추가한다.
•
큐가 가득 차 있는 경우 새요 청은 버린다.
•
지정된 시간마다 큐에서 요청을 꺼내어 처리한다.
▪
누출 버킷 알고리즘은 다음 두 인자를 필요로 한다.
•
버킷 크기 : 큐 사이즈의 값
•
처리율 : 지정된 시간당 몇 개의 항목을 처리할 지 지정하는 값이다. 보통 초 단위로 표현한다.
◦
장점
▪
큐의 크기가 제한되어 있어 메모리 사용량 측면에서 효율적이다.
▪
고정된 처리율을 가족 있으므로 안정적 출력이 필요한 경우 적합하다.
⇒ 안정적 출력?
◦
단점
▪
단시간에 트래픽이 몰리는 경우, 큐에는 오래된 요청들이 쌓이게 되고 최신 요청들은 버려지게 된다.
▪
이 역시, 인자 튜닝 관련한 이슈가 있을 수 있다.
•
고정 윈도 카운터 알고리즘
◦
정의
▪
타임라인을 고정된 간격의 윈도라는 단위로 나누고, 각 윈도마다 카운터를 붙인다.
▪
이 카운터는 요청이 접수될 때마다 1씩 증가하며, 카운터의 값이 임계치에 도달하는 경우, 새로운 요청은 새로운 윈도가 열리기까지 버려진다.
◦
장점
▪
메모리 효율이 좋다.
▪
이해하기 쉽다.
▪
윈도가 닫히는 시점에, 카운터를 초기화하는 방식은 특정한 트래픽 패턴을 처리하기에 적합하다.
◦
단점
▪
윈도 경계 부근에서 일시적으로 많은 트래픽이 몰리는 경우, 기대한 처리율보다 더 많은 양의 요청을 처리하게 된다.
•
윈도를 00초부터 1분 간격으로 정하고 5개를 처리한다고 했을 때,
•
요청이 55 ~ 05초 사이에 10개가 들어온다면 모두 처리가 된다. 이는 당초 1분마다 5개 씩 처리되기 바랬던 기존의 처리양의 2배를 처리하게 된다.
•
이동 윈도 로깅 알고리즘
◦
정의
▪
레디스의 정렬 집합 같은 캐시에 요청의 타임스탬프 데이터를 보관하고, 이를 처리에 사용하여 특정 트래픽이 몰림을 방지하는 알고리즘이다.
▪
새 요청이 오면 만료된 타임스탬프는 제거한다. 만료된 타임스탬프는 그 값이 현재 윈도의 시작 시점보다 오래된 타임스탬프를 말한다.
▪
요청의 타임스탬프를 로그에 추가하고, 로그의 크기가 허용치보다 같거나 작으면 요청을 시스템에 전달한다. 그렇지 않은 경우, 처리를 거부한다.
◦
장점
▪
어느 순간의 윈도를 보더라도, 허용되는 요청의 개수는 시스템의 처리율 한도를 넘지 않는다.
◦
단점
▪
메모리 효율이 좋지 않다. 거부된 요청의 타임스탬프도 저장해두기 때문이다.
•
이동 윈도 카운터 알고리즘
◦
정의
▪
고정 윈도 카운터와 이동 윈도 로깅 알고리즘을 결합한 것이다.
▪
간략하게 말해서 요청이 발생할 때마다 현재 1분간의 요청 수 + (직전 1분간의 요청 수 * 이동 윈도와 직전 1분이 겹치는 비율)의 수로 윈도에 존재하는 요청을 계산한다.
•
만약 00초부터 1분간 윈도를 설정한다 가정하고 현재 0 ~ 1분 동안 요청 5개, 현재 1분 30초 요청 2개라고 하면
•
5 * 50% + 2 = 4.5가 된다. 반올림, 내림은 재량껏 결정하면 된다. 이 값이 현재 임계치, 즉, 분당 처리율 한도보다 낮거나 같으면 받아들인다.
◦
장점
▪
이전 시간대의 평균 처리율에 따라 현재 윈도의 상태를 계산하므로 짧은 시간동안 몰리는 트래픽에도 잘 대응한다.
▪
메모리 효율이 좋다.
◦
단점
▪
직전 시간대에 도착한 요청이 균등하게 분포되어 있는 경우를 가정하고 추정치를 계산하기 때문에, 문제가 발생할 수 있다.
개략적인 아키텍처
•
처리율 제한 알고리즘이 제공해야 하는 기능은 단순하다. 얼마나 많은 요청이 접수되었는지를 추적할 수 있는 카운터를 추적 대상(IP 주소, 디바이스, 사용자 식별자 등)의 경로마다 두고 한도를 넘어서면 거부하는 것이다.
•
그렇다면 이 카운터는 어느 곳에 보관할 것인가? 일반적으로 처리 속도 때문에 메모리 상에 적재되어 있는 캐시 메모리가 적합할 것인데, 대표적으로 레디스를 자주 사용한다.
3단계 상세 설계
•
개략적 설계만으로 부족한 내용들을 설계하는 단계다. 대표적으로 다음과 같은 사항들을 결정해야 한다.
◦
처리율 제한 규칙은 어떻게 만들어지고 어디에 저장되는가?
◦
처리가 제한된 요청들은 어떻게 처리되는가?
처리율 제한 규칙
•
결국, 예외를 설정하는 부분이므로 사용자 시나리오를 고려하거나, 서버의 스펙을 고려하여 결정해야 한다.
◦
따닥을 방지할 수도 있겠다.
처리율 한도 초과 트래픽의 처리
•
한도 제한에 걸리면 429 응답을 클라이언트에게 보내는 것이 일반적이나, 경우에 따라서는 한도 제한에 걸린 요청들을 큐에 저장해두고 추후 처리되도록 할 ㅜㅅ 있다.
•
커스텀 헤더를 제공하여 클라이언트에게 처리 가능한 요청의 수를 보내거나, 요청의 제한을 보내는 등의 작업이 가능하다.
상세 설계
•
처리율 제한 규칙은 디스크에 보관한다. 보통, 배포되는 시스템에 필요하므로 환경변수 파일로 관리하는 것이 적합할 것이다.
•
클라이언트가 요청을 서버에 보내면 요청을 미들웨어가 먼저 처리할 것이다.
•
처리율 제한 미들웨어는 제한 규칙과 관련한 변수들을 캐시에서 가져온다. 가져온 값들에 근거하여 다음과 같은 결정을 내린다.
◦
해당 요청이 처리율 제한에 걸리는 경우, 429나 메시지 큐에 보관한다.
◦
그렇지 않은 경우, 요청을 처리한다.
분산 환경에서의 처리율 제한 장치 구현
•
분산 환경의 경우, 고려해야할 사항이 더 추가된다. 일반적으로 다음 두 가지를 더 고려해야 한다.
◦
경쟁 조건
◦
동기화
경쟁 조건
•
레디스나 메모리에 카운터를 저장해두고 사용하는 경우, 해당할 것이다.
•
락을 사용하는 것이 대표적이며 락 대신 사용할 수 있는 방안으론 루아 슼릡트, 정렬 집합을 사용하는 것이다.
동기화 이슈
•
처리율 제한 장치를 여럿 두게 되는 경우, 발생할 수 있는 문제다.
•
처리율 제한 장치가 참조하는 레디스를 중앙 집중형으로 설계하여 방지할 수 있다.
성능 최적화
•
두 가지 지점에서 개선 시도가 가능하다.
•
처리율 제한 장치의 지연시간을 줄이기 위해 물리적으로 근거리에 처리율 제한 장치를 둔다.
•
제한 장치 간의 동기화를 위해 최종 일관성 모델을 사용한다.
◦
이는, 6장의 키-값 저장소 설계에서 데이터 일관성을 참고하자.
모니터링
•
기본적으로 처리율 제한 장치를 모니터링함으로써 얻고자 하는 정보들은 다음과 같다.
◦
채택된 처리율 제한 알고리즘이 효과적인지
◦
정의한 처리율 제한 규칙이 효과적인지
•
모니터링을 위해 해당 정보들을 제공하면서 적절히 튜닝할 수 있도록 해야 한다.
4단계 마무리
•
처리율 제한을 구현하는 알고리즘과 그 장, 단점들을 다뤘으며 알고리즘 외에도 아키텍처, 분산환경에서의 처리율 제한 장치, 성능 최적화, 모니터링 등을 다뤘다.
•
다음과 같은 부분을 추가적으로 찾아보면 개선할 부분을 찾을 수 있을 것이다.
◦
경성 또는 연성 처리율 제한
▪
경성 처리율 제한 : 요청의 개수는 임계치를 넘을 수 없다.
▪
연성 처리율 제한 : 요청의 개수는 잠시 동안만은 임계치를 넘을 수도 있다.
◦
다양한 계층에서의 처리율 제한
▪
애플리케이션 계층이 아닌, 계층에서의 처리율 제한을 시도해볼 수 있다.
▪
Iptables를 사용한 IP 주소에 처리율 제한을 거는 등 말이다.
◦
처리율 제한을 회피하기 위해 클라이언트 측의 설계를 고려해볼 수 있다.
▪
클라이언트 측 캐시를 사용하여 API 호출 횟수를 줄인다던가.
▪
임계치를 이해하고 클라이언트 측에서 API 호출을 제어한다던가.
▪
재시도 로직을 구현하는 경우, 충분한 재시도 시간을 튜닝한다던가.