처리율 제한 장치
1. 처리율 제한 장치란
- 클라이언트 또는 서비스가 보내는 트래픽의 처리율을 제어하는 장치
- 일정 시간 동안 허용되는 요청 수를 제한하는 방식
- 웹 서버, API 게이트웨이, 로드밸런서, 방화벽 등에 프로그램 로직으로 구현 가능

2. 처리율 제한 장치의 장점
2.1 DoS 공격으로 인한 자원 고갈 방지
- 과도한 요청으로부터 서버 자원 보호
- CPU, 메모리, 네트워크, 데이터베이스 연결 등의 고갈 방지
- 악의적인 요청뿐 아니라 비정상적인 클라이언트 동작에도 대응 가능
2.2 비용 절감
- 불필요한 서버 확장 방지
- 유료 외부 API 호출 횟수 제한
- 처리 가능한 요청만 백엔드 서비스로 전달
2.3 서버 과부하 방지
- 서버가 처리할 수 있는 수준으로 요청량 조절
- 급격한 트래픽 증가로 인한 장애 방지
- 서비스 안정성 및 응답 시간 유지
3. 처리율 제한 방식
처리율 제한은 요청 속도를 제어하는 주체에 따라 클라이언트 측 제한과 서버 측 제한으로 구분 가능
3.1 클라이언트 측 제한
3.2 서버 측 제한
3.3 클라이언트 측 제한과 서버 측 제한의 병행
-
실제 서비스에서는 두 방식을 함께 적용 가능
-
클라이언트 측 제한
- 불필요한 요청 발생 억제
- 사용자 경험 및 네트워크 효율 개선
-
서버 측 제한
- 클라이언트의 우회 또는 비정상 동작으로부터 시스템 보호
- 최종적인 처리율 제한 정책 강제
4. 시스템 요구사항
4.1 기능 요구사항
- 서버 측 API를 위한 처리율 제한 장치 설계
- 다양한 형태의 제어 규칙 지원
- 요청 제한 시 클라이언트에게 제한 사실 전달
- 서비스별 처리율 제한 정책 설정 지원
4.2 비기능 요구사항
- 대규모 요청 처리 가능
- 가능한 한 적은 메모리 사용
- 분산 환경에서 동작
- 높은 가용성 확보
- 처리율 제한 기능으로 인한 응답 지연 최소화
4.3 배포 방식
- 처리율 제한 장치를 독립된 서비스로 구현 가능
- 애플리케이션 서버 또는 API 게이트웨이에 종속된 기능으로 구현 가능
- 시스템 환경, 운영 규모, 성능 요구사항에 따라 적절한 방식 선택 필요
독립된 서비스로 구현하는 경우
- 여러 서비스의 처리율 제한 정책을 중앙에서 관리 가능
- 처리율 제한 로직을 각 애플리케이션과 분리 가능
- 여러 서비스에서 공통 기능으로 재사용 가능
- 처리율 제한 기능만 독립적으로 확장하거나 배포 가능
애플리케이션 또는 API 게이트웨이에 포함하는 경우
- 별도의 네트워크 호출이 필요하지 않아 지연 시간 감소 가능
- 시스템 구성과 운영 복잡도 감소
- 애플리케이션 또는 게이트웨이의 기존 인증·라우팅 정보 활용 가능
- 소규모 시스템이나 서비스별 정책이 다른 환경에 적용하기 쉬움
선택 시 고려 사항
-
독립된 서비스는 중앙 관리와 재사용에 유리하지만 추가적인 네트워크 지연과 장애 지점 발생 가능
-
종속된 방식은 구현이 단순하지만 서비스마다 로직이 중복될 가능성 존재
-
독립 여부와 관계없이 처리율 제한 장치 장애에 대한 정책 필요
- 장애 발생 시 요청을 허용하는
fail-open
- 장애 발생 시 요청을 차단하는
fail-closed
5. API 게이트웨이와 처리율 제한
5.1 API 게이트웨이의 역할
5.2 완전 관리형 API 게이트웨이
- 클라우드 사업자가 API 게이트웨이를 완전 관리형 서비스로 제공하는 경우가 많음
- 서버 설치와 운영 부담 감소
- 처리율 제한, 인증, 모니터링 등의 기능을 설정 방식으로 적용 가능
- 사용하는 제품에 따라 지원 기능과 처리율 제한 알고리즘에 차이 발생 가능
5.3 MSA에서의 활용
- MSA에서는 처리율 제한 장치를 API 게이트웨이에 구현하는 경우가 많음
- 클라이언트 요청이 각 마이크로서비스에 도달하기 전에 공통 정책 적용 가능
- 각 마이크로서비스에 처리율 제한 로직을 중복 구현하는 문제 감소
- 서비스 전체의 처리율 제한 정책을 중앙에서 관리 가능
5.4 처리율 제한 장치의 위치를 결정할 때 고려할 사항
- 처리율 제한 장치를 어디에 배치할지는 서비스 상황과 목표에 따라 결정
- 모든 시스템에 적용되는 단일한 정답은 없음
구현 환경
- 현재 사용하는 프로그래밍 언어와 프레임워크가 서버 측 처리율 제한 구현에 적합한지 확인
- 높은 요청량에서도 충분한 성능을 제공할 수 있는지 확인
알고리즘 선택권
- 직접 구현할 경우 필요한 알고리즘을 자유롭게 선택 가능
- 외부 API 게이트웨이를 사용할 경우 제공되는 알고리즘과 설정 방식에 제약 발생 가능
기존 아키텍처
- MSA에 API 게이트웨이가 이미 포함된 경우 게이트웨이에 처리율 제한 기능 추가 가능
- 공통 정책의 중앙 관리 가능
개발 및 운영 인력
- 직접 구현하고 운영할 인력이 부족한 경우 상용 API 게이트웨이 활용 가능
- 개발 비용과 운영 복잡도 감소 가능
6. 처리율 제한 알고리즘
- 토큰 버킷
- 누출 버킷
- 고정 윈도 카운터
- 이동 윈도 로그
- 이동 윈도 카운터
7. 토큰 버킷 알고리즘
7.1 기본 개념
- 지정된 용량을 갖는 버킷 사용
- 버킷 내부에 요청 처리 권한을 의미하는 토큰 저장
- 사전에 설정된 공급률에 따라 토큰 추가
- 버킷이 가득 찬 경우 추가 토큰 폐기
7.2 동작 원리
- 요청 도착
- 버킷에 토큰이 있는지 확인
- 토큰이 있으면 토큰 하나 소비
- 요청을 시스템에 전달
- 토큰이 없으면 요청 거부 또는 폐기
7.3 주요 인자
버킷 크기
- 버킷에 저장할 수 있는 토큰의 최대 개수
- 순간적으로 허용할 수 있는 최대 요청량과 관련됨
토큰 공급률
- 일정 시간 마다 버킷에 추가되는 토큰 수
- 장기적으로 허용되는 평균 요청 처리율과 관련됨
7.4 버킷 구성
7.5 장점
- 구현이 비교적 간단함
- 메모리 사용량이 적음
- 일정 범위의 순간적인 트래픽 증가 허용 가능
- 평균 처리율을 유지하면서 버스트 트래픽 처리 가능
7.6 단점
- 버킷 크기와 토큰 공급률의 적절한 설정이 어려움
- 잘못된 인자 설정 시 정상 요청이 과도하게 거부될 수 있음
8. 누출 버킷 알고리즘
8.1 기본 개념
- 요청을 큐에 저장한 후 일정한 속도로 처리
- 일반적으로 FIFO 큐로 구현
- 출력 처리율이 일정하게 유지됨
8.2 동작 원리
- 요청 도착
- 큐에 빈자리가 있는지 확인
- 빈자리가 있으면 요청을 큐에 추가
- 큐가 가득 찬 경우 새로운 요청 폐기
- 일정한 주기마다 큐에서 요청을 꺼내 처리
8.3 주요 인자
버킷 크기
처리율
- 일정 시간 동안 큐에서 처리하는 요청 수
- 일반적으로 초 단위로 설정
8.4 토큰 버킷과의 차이
-
토큰 버킷
-
누출 버킷
- 요청을 일정한 속도로 꺼내 처리
- 출력 처리율이 상대적으로 일정함
8.5 장점
- 큐 크기가 제한되어 있어 메모리 사용량 예측 가능
- 일정한 출력 처리율 제공
- 안정적인 요청 처리 속도가 필요한 시스템에 적합
8.6 단점
- 단시간에 트래픽이 몰리면 큐에 오래된 요청 누적
- 큐가 가득 차면 새로운 요청 폐기
- 큐 크기와 처리율 설정이 어려움
- 큐 대기로 인해 응답 지연 증가 가능
9. 고정 윈도 카운터 알고리즘
9.1 기본 개념
- 시간을 일정한 크기의 고정 구간으로 분할
- 각 구간마다 요청 수를 기록하는 카운터 사용
9.2 동작 원리
- 요청 도착
- 현재 윈도의 카운터를 1 증가
- 카운터가 설정된 한도 이하이면 요청 허용
- 한도를 초과하면 새로운 윈도가 시작될 때까지 요청 거부
- 새로운 윈도가 시작되면 카운터 초기화
9.3 장점
- 구현이 간단함
- 이해하기 쉬움
- 카운터 하나만 저장하면 되므로 메모리 효율이 높음
- 일정한 시간 단위로 요청량을 관리하는 정책에 적합
9.4 단점
- 윈도 경계에서 처리율 한도를 초과할 수 있음
- 이전 윈도 마지막 시점과 다음 윈도 시작 시점에 요청이 집중될 경우 문제 발생
- 실제 연속 시간 기준으로는 설정한 한도보다 많은 요청 허용 가능
10. 이동 윈도 로그 알고리즘
10.1 기본 개념
- 각 요청의 타임스탬프를 개별적으로 기록
- Redis 정렬 집합과 같은 자료구조 활용 가능
10.2 동작 원리
- 새로운 요청 도착
- 현재 윈도의 시작 시점보다 오래된 타임스탬프 제거
- 새로운 요청의 타임스탬프를 로그에 추가
- 로그에 저장된 요청 수 확인
- 요청 수가 허용치 이하이면 요청 전달
- 허용치를 초과하면 요청 거부
10.3 장점
- 고정 윈도 카운터의 경계 문제 해결
- 현재 시점을 기준으로 정확한 시간 범위 계산 가능
- 어느 시점에서 윈도를 계산해도 요청 수가 설정 한도를 넘지 않도록 제어 가능
10.4 단점
- 각 요청의 타임스탬프를 저장해야 함
- 요청량이 많을수록 메모리 사용량 증가
- 거부된 요청의 타임스탬프까지 저장하는 구현에서는 추가 메모리 사용 발생
11. 이동 윈도 카운터 알고리즘
11.1 기본 개념
- 고정 윈도 카운터와 이동 윈도 로그의 특징을 결합한 방식
- 현재 윈도와 직전 윈도의 카운터를 이용하여 현재 시간 범위의 요청 수 추정
11.2 동작 원리
- 예를 들어 시간을 1분 단위의 고정 구간으로 분할
- 이전 1분 구간과 현재 1분 구간의 요청 수 저장
- 이전 구간의 요청을 모두 포함하지 않음
- 현재 시점과 가까운 부분만 시간 비율에 따라 반영
- 직전 윈도의 요청이 윈도 전체에 균등하게 분포한다고 가정
11.3 계산 예시
- 처리율 제한: 분당 100개
- 현재 시각: 현재 윈도가 시작된 후 20초 경과
- 직전 윈도 요청 수: 90개
- 현재 윈도 요청 수: 30개
- 직전 윈도에서 현재 이동 윈도와 겹치는 비율: 40초 ÷ 60초
- 추정 요청 수
90 × (40 ÷ 60) + 30 = 90개
11.4 장점
- 이전 시간대의 평균 처리율에 따라 현재 윈도의 상태 계산
- 짧은 시간에 몰리는 트래픽에 효과적으로 대응
- 요청별 타임스탬프를 모두 저장할 필요 없음
- 이동 윈도 로그보다 메모리 사용량이 적음
- 고정 윈도의 경계 문제 완화
11.5 단점
- 직전 윈도의 요청이 균등하게 분포했다고 가정
- 실제 요청 분포와 계산된 추정치 사이에 오차 발생 가능
- 실험 결과에서는 이러한 오차가 심각한 문제로 나타나지 않음
12. 처리율 제한 데이터 저장소
12.1 데이터베이스 사용의 한계
- 처리율 제한 여부를 확인하기 위한 카운터 필요
- 모든 요청마다 카운터 조회 및 갱신 필요
- 디스크 기반 데이터베이스 사용 시 지연 시간 증가 가능
- 높은 요청량에서 데이터베이스 부하 증가 가능
12.2 인메모리 캐시 활용
- 일반적으로 Redis와 같은 인메모리 저장소 활용
- 빠른 읽기 및 쓰기 가능
- 만료 시간 설정 가능
- 카운터와 타임스탬프 자료구조 지원
- 여러 처리율 제한 장치가 데이터를 공유하기 쉬움
13. 처리율 제한 규칙 관리
13.1 제한 규칙의 구성
-
각 서비스의 요구사항에 따라 규칙 설정
-
규칙에 포함될 수 있는 항목
- 제한 대상
- 요청 허용량
- 시간 윈도 크기
- API 경로
- 사용자 등급
- 초과 요청 처리 방식
13.2 규칙 저장
- 규칙을 설정 파일 형태로 디스크에 저장 가능
- 처리율 제한 장치가 설정 파일을 주기적으로 읽어 규칙 갱신 가능
14. 한도 초과 요청 처리
14.1 HTTP 상태 코드
- 처리율 제한을 초과한 요청에
HTTP 429 Too Many Requests 응답 반환
- 클라이언트에게 요청 한도 초과 사실 전달
14.2 응답 헤더
14.3 초과 요청의 보관
- 제한된 요청을 즉시 폐기하지 않고 메시지 큐에 저장 가능
- 나중에 비동기 방식으로 처리 가능
- 모든 API 요청에 적용되는 방식은 아님
- 주문, 작업 실행 등 비동기 처리가 가능한 요청에 적합

15. 분산 환경에서의 처리율 제한
15.1 주요 문제
16. 경쟁 조건
16.1 경쟁 조건의 발생 과정
- 현재 카운터 값 조회
- 한도 초과 여부 확인
- 카운터 값 증가
- 여러 요청이 위 과정을 동시에 수행할 경우 동일한 카운터 값을 읽을 수 있음
- 실제 요청 수보다 카운터가 적게 증가하는 문제 발생 가능
- 허용 한도를 초과한 요청이 통과할 수 있음
16.2 락 사용
- 공유 데이터에 락을 적용하여 한 번에 하나의 요청만 수정하도록 제한 가능
- 경쟁 조건 방지 가능
- 높은 동시성 환경에서는 대기 시간과 성능 저하 발생 가능
16.3 Lua 스크립트와 Redis 정렬 집합
- 앞서 설명한 설계에서는 경쟁 조건의 해결책으로 Lua 스크립트와 Redis의 정렬 집합 활용 가능
Lua 스크립트
- 조회, 비교, 증가 작업을 하나의 Lua 스크립트에 포함
- 여러 Redis 명령을 하나의 작업처럼 실행
- Redis 서버 내부에서 실행
- 조회·판단·갱신 과정의 원자적 실행 가능
Lua 언어
- 작고 가벼운 프로그래밍 언어
- 다른 프로그램 내부에 삽입하여 사용하기 적합
- Redis 내부에서 데이터 처리 로직을 실행할 때 활용 가능
Redis 정렬 집합
- 각 데이터에 점수를 붙여 점수 순서대로 자동 정렬하는 자료구조
- 처리율 제한에서는 요청 시간을 점수로 저장
- 특정 시간 범위에 포함되는 요청만 조회 가능
- 최근 요청 수를 정확하게 계산하는 데 활용 가능
17. 서버 간 상태 동기화
17.1 문제 상황
- 처리율 제한 장치 서버를 여러 대 운영할 경우 서버마다 서로 다른 카운터를 가질 수 있음
- 같은 클라이언트의 요청이 여러 서버로 분산되면 전체 요청량을 정확하게 계산하기 어려움
17.2 고정 세션 활용
- 같은 클라이언트의 요청을 항상 같은 처리율 제한 장치로 전달
- 서버별 로컬 카운터 사용 가능
한계
- 특정 서버에 요청이 집중될 수 있음
- 서버 장애 시 상태 이전이 어려움
- 확장성과 유연성이 낮음
- 처리율 제한만을 위해 고정 세션을 사용하는 것은 권장하기 어려움
17.3 중앙 집중형 데이터 저장소 활용
- Redis와 같은 중앙 집중형 데이터 저장소 사용
- 여러 처리율 제한 장치가 동일한 카운터 공유
- 요청이 어느 서버에 도착하더라도 같은 제한 상태 확인 가능
- 분산 환경에서 비교적 일관된 처리율 제한 제공 가능

18. 성능 및 분산 환경 고려 사항
18.1 여러 데이터센터 지원
- 사용자와 가까운 데이터센터에서 요청 처리
- 네트워크 지연 시간 감소
- 지역별 처리율 제한 장치 배치 가능
- 특정 데이터센터에 요청이 집중되는 문제 완화 가능
18.2 최종 일관성 모델 활용
- 데이터센터 사이의 처리율 제한 상태를 비동기적으로 동기화
- 모든 데이터센터의 상태를 즉시 동일하게 맞추지 않아도 됨
- 데이터 동기화로 인한 지연 시간과 통신 비용 감소 가능
- 데이터센터 사이의 상태가 일시적으로 다를 수 있음
- 동기화가 완료되기 전까지 전체 처리율 한도를 순간적으로 초과할 가능성 존재
- 정확한 전역 제한보다 낮은 지연 시간과 높은 가용성이 중요한 환경에 적합
19. 모니터링
19.1 모니터링 목적
- 처리율 제한 장치가 효과적으로 동작하는지 확인
- 설정한 알고리즘이 예상대로 동작하는지 확인
- 처리율 제한 규칙이 지나치게 엄격하거나 느슨하지 않은지 확인
19.2 주요 모니터링 항목
- 전체 요청 수
- 허용된 요청 수
- 거부된 요청 수
- HTTP 429 응답 비율
- 사용자 또는 API별 제한 발생 횟수
- 처리율 제한 검사 지연 시간
- Redis 조회 및 갱신 지연 시간
- 규칙별 한도 사용률
19.3 모니터링 결과의 활용
- 지나치게 많은 정상 요청이 거부되는 경우 제한 규칙 완화
- 서버 과부하가 계속 발생하는 경우 제한 강화
- 예상하지 못한 트래픽 패턴 발견
- 알고리즘 또는 주요 인자 조정
20. 경성 처리율 제한과 연성 처리율 제한
20.1 경성 처리율 제한
- 설정된 처리율 한도를 초과하는 요청을 허용하지 않는 방식
- 한도에 도달하면 이후 요청을 즉시 거부
- 엄격한 자원 보호가 필요한 경우에 적합
- 순간적인 트래픽 증가를 허용하기 어려움
20.2 연성 처리율 제한
- 설정된 한도를 일시적으로 초과하는 요청을 일정 범위까지 허용하는 방식
- 짧은 시간 동안 발생한 버스트 트래픽 수용 가능
- 사용자 요청을 유연하게 처리할 수 있음
- 허용 범위를 지나치게 크게 설정하면 서버 과부하 발생 가능