API 과부하 방지의 핵심, 처리율 제한 장치 설계 가이드
이번 글에서는 네트워크 시스템에서의 처리율 제한 장치(Rate Limiter)를 설계한 아키텍쳐 다이어그램을 중심으로 설명드리도록 하겠습니다. 😀
1. 처리율 제한 장치란?
클라이언트 또는 서비스가 보내는 트래픽의 처리율(rate)를 제어하기 위한 장치입니다.
예를 들어 HTTP의 경우, 특정 기간 내 전송되는 클라이언트의 요청 횟수를 제한하는 것이죠.
요청 횟수가 제한 장치에 정의된 임계치(threshold)를 넘어서면 추가로 도달한 모든 호출은 처리가 중단(block)됩니다.
사례
- 사용자는 초당 2회 이상 새 글을 올릴 수 없다.
- 같은 IP주소로는 하루에 계정을 10개 이상 만들 수 없다.
- 같은 디바이스로는 금융어플리케이션에서 30분 내에 이체를 2번 이상 할 수 없다.
2. 처리율 제한 장치의 장점
API에 처리율 제한 장치를 두면 좋은 점 입니다!
- DoS 공격에 의한 자원 고갈 방지
- API 요청 횟수 제한을 둠으로써 방지할 수 있다.
- 비용 절감
- 추가 요청에 대한 제한을 두니, 서버를 많이 두지 않아도 된다.
- 특히, Third-party API에 대한 사용료 지불 중인 경우 과금을 아낄 수 있다.
- 서버 과부하 방지
- 봇으로부터의 트래픽이나 사용자의 잘못된 이용 패턴으로 유발된 트래픽을 제어할 수 있다.
3. 처리율 제한 설계
처리율 제한 알고리즘의 기본 아이디어는 단순합니다.
- 얼마나 많은 요청이 접수되었는지 추척할 수 있는 카운터를 정한다.
- 추적 카운터를 추적 대상 별로 둔다. (추적 대상: 사용자별, IP 주소별, API 엔드포인트/서비스 단위)
- 처리 한도에 대한 제한 규칙을 세운다.
- 카운터의 값이 한도를 넘어서면 한도를 넘어 도착한 요청을 거부한다.
위 기본 아이디어에 기반하여 설계한 다이어그램입니다.
1. 처리율 제한 규칙을 디스크에 보관한다. 작업 프로세스(workers)는 수시로 규칙을 디스크에서 읽어 캐시에 저장한다.
처리율 제한 규칙은
리프트(Lyft)
와 같은 처리율 제한에 대한 오픈 소스를 이용할 수 있습니다.처리율 제한 규칙은 디스크 설정파일에 보관합니다.
예시 : “클라이언트가 분당 5회 이상 로그인할 수 없도록 제한”
1 2 3 4 5 6 7
domain: auth # 추적대상: 권한(사용자) descriptiors: - key: auth_type # 사용자에 따라 value: login # 로그인을 rate_limit: unit: minute # 1분에 requests_per_unit: 5 # 5번까지
2. 클라이언트가 요청을 서버에 보내면 먼저 처리율 제한 미들웨어에 도달하여 처리한다.
현재 구조는 API Gateway와 같은 미들웨어를 사용한 방식이다. 필요에 따라API 서버 내에서 자유로운 알고리즘으로 구현해둘 수도 있다. (알고리즘: 토큰 버킷, 누출 버킷, 고정 윈도 카운터 등..)
구분 API Gateway API Server 구현 위치 클라이언트와 서버 사이의 중앙 게이트웨이 API 서버 내부 역할 모든 트래픽에 대한 통합 제어 서버별 독립적 제어 장점 - 시스템 전체 부하 분산
- 서버 도달 전 요청 차단
- 확장성 있는 분산 카운터 관리- 서비스별 세밀한 제어
- 설계 복잡성 감소단점 - 단일 장애점 가능성
- 추가 레이턴시 발생- 코드 중복 가능성
- 분산 환경 동기화 복잡사용 사례 - 다중 서비스 통합 관리
- 외부 요인(IP, API 키) 기반 제한- 서비스 고유 규칙 필요
- 단순 아키텍처예시 기술 AWS API Gateway, Kong, Nginx Express.js, Spring Boot, Django REST Framework 시스템이 분산 환경인 경우 처리율 제한 장치를 여러 서버나 프로세스에서 공유할 수 있도록 중앙화 해야한다. (아래
Deep Dive
에 자세한 설명이 있습니다.)
3. 처리율 제한 미들웨어는 제한 규칙을 캐시에서 가져온다. 또한 추적할 수 있는 카운터(카운터 및 마지막 요청의 타임스탬프)를 레디스 캐시에서 가져온다.
- 추적 카운터는 빠른 접근과 시간 기반 만료 기능이 필요하므로 메모리 기반 캐시(예: Redis, Memcached)가 적합하다.
4. 제한 규칙과 추적 카운터를 기반으로 미들웨어는 성공/스로톨링 중 결정을 내려 처리한다.
허용: 처리율 제한에 걸리지 않은 경우, 요청을 API 서버로 전달한다.
차단 (Throttling): 처리율 제한에 걸린 경우, HTTP 429(Too many Requests) 에러를 클라이언트에 전송한다.
초과된 요청을 즉시 버릴 수도 있고,
필요에 따라 MQ(메시지 큐)에 보관했다가 나중에 처리할 수도 있다.
🌊 Deep Dive! 분산 시스템에서의 처리율 제한 장치 구현
분산 시스템에서의 처리율 제한 장치를 구현할 때는 아래 두 키워드에 대한 문제를 고려해보아야 합니다.
경쟁 조건
동기화 조건
각 문제 조건은 어떨 때 발생하며, 어떻게 해결할 수 있을까요?
경쟁 조건 (Race Condition)
- 여러 서버 또는 프로세스가 동시에 요청을 처리할 때, 동일한 카운터를 갱신하는 과정에서 경쟁 조건이 발생할 수 있습니다.
예를 들어, 동일한 사용자가 동시에 여러 요청을 보낼 경우, 각 서버가 독립적으로 요청을 허용하면 제한 규칙이 제대로 적용되지 않을 수 있습니다.
해결 방법:
- 분산 락 (Distributed Lock): 시스템의 성능을 상당히 저하시키기 때문에 비추!
- 루아 스크립트(Lua Script)
- 레디스 자료구조 중 정렬집합(Sorted Set) 활용
동기화 조건 (Synchronization Issue)
- 분산 환경에서는 여러 서버가 동일한 사용자 또는 API 키에 대한 요청을 처리하는데, 처리율 제한 상태를 실시간으로 동기화하는 것이 어려움이 있습니다.
- 예를 들어, A 서버와 B 서버가 동일한 사용자의 요청을 받아 처리하는 경우, 두 서버가 서로 최신 카운터 값을 알지 못하면 제한이 제대로 적용되지 않을 수 있습니다.
- 고정 세션(Sticky Session) 활용: 클라이언트 요청과 처리율 제한 장치를 고정해두는 방식이지만, 확장과 유연성에서 나쁘기 때문에 비추!
- 중앙 집중형 저장소: Redis, Memcached와 같은 캐시 서버를 사용해 실시간으로 요청 횟수를 동기화
참고
- 책:
<가상면접 사례로 배우는 대규모 시스템 설계 기초>
4장_처리율 제한 장치의 설계