4. 처리율 제한 장치
요청 회수가 제한장치에 정의된 임계치를 넘어서면 추가로 도달한 모든 호출에 대해서 처리가 중단됨.
장점
DoS 공격 방지
비용 절감
서버 과부하 방지
1. 문제 이해 및 설계 범위 확정
면접관에게 질문
클라이언트 or 서버 측 제한 장치?
서버
어떤 기준을 통해서 호출을 제어해야하나?
다양한 규칙이 있을 수 있음.
시스템 규모, 스타트업 or 대규모?
대규모요청
시스템이 분산 환경에서 동작해야하나?
그렇다.
처리율 서비스가 독립된 서비스?
알아서
사용자의 요청이 처리율 제한 장치에 의해 걸리진 경우, 알려줘야하나?
그렇다.
요구사항
설정된 처 리율을 초과하는 요청은 정확하게 제한
낮은 응답시간
가능한 한 적은 메모리
하나의 처리율 제한 장치를 여러 서버나 프로세스에서 공유
요청이 제한되었을 때는 그 사실을 사용자에게 분명하게 보여줘야함
제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어서는 안 됨.
2. 개략적 설계안 제시, 동의 구하기
처리율 제한 장치 시스템을 미들웨어에 둘 수도 있고,
API 서버와 같은 레벨에 둘 수 도 있음.
처리율 제한 알고리즘
토큰 버킷 (Token Bucket)
미리 정해진 용량의 '버킷'에 주기적으로 '토큰'이 채워짐
토근이 가득차면, 추가되는 토근은 버려짐
토큰을 하나씩 꺼내 사용하며, 토큰이 있어야만 요청이 처리됨.
버킷에 토큰이 없으면 요청은 거부되거나 대기
요청이 없을 때 토큰을 모아둘 수 있어, 일시적인 대량 요청(burst)을 유연하게 처리
버킷 크기, 토큰 공급률 이 값을 적절하게 튜닝하는 것이 어려운 일
e.g. Spring resilience4j
누수 버킷 (Leaky Bucket)
요청이 들어오면 '버킷'에 쌓이고, 버킷에서는 정해진 속도(rate)로 요청이 빠져나가 처리됨
보통 FIFO 큐로 구현됨.
큐 크기가 제한되어있기 때문에 메모리 사용량 측면에서 효율적
버킷이 가득 차면 새로 들어오는 요청은 버려짐
요청을 고정된 속도로 처리하므로 안정적인 출력 속도를 보장
일시적인 대량 요청을 처리하기 어렵다는 단점
고정 윈도우 카운터 (Fixed Window Counter)
정해진 시간 간격('윈도우') 동안의 요청 수를 셈
이 숫자가 임계치를 넘으면 해당 윈도우가 끝날 때까지 들어오는 모든 요청을 막음.
알고리즘을 이해하기 쉽다는 장점
윈도우의 경계 시점에서 순간적으로 허용량의 2배에 달하는 요청이 처리될 수 있는 단점
![[Pasted image 20250727150609.png]]
슬라이딩 윈도우 로그 (Sliding Window Log)
각 요청의 타임스탬프를 기록하고, 현재 시간을 기준으로 지난 1분(또는 설정된 시간) 동안의 요청 수를 세어 임계치와 비교
정확하게 처리율을 제어할 수 있지만, 모든 요청의 타임스탬프를 저장해야 하므로 메모리 사용량이 많다는 단점
슬라이딩 윈도우 카운터 (Sliding Window Counter)
고정 윈도우 카운터와 슬라이딩 윈도우 로그의 장점을 결합한 방식
이전 윈도우와 현재 윈도우의 요청 수를 가중 평균하여 현재 요청 가능 여부를 판단
장점 이 전 시간대의 평균 처리율에 기반하여 현재 윈도 상태 판단.
즉 짦은 시간 몰리는 트래픽에도 잘 대응한다.
단점, 추정치 계산이 다소 느슨함
왜?
직전 시갠대에 도착한 요청이 균등하게 분포되어있다고 가정하기 때문에
개략적인 아키텍쳐
![[Pasted image 20250727151013.png]]
클라이언트 -> 미들웨어
미들웨어 -> 레디스
레디스의 지정 버킷에서 카운터를 가져와서 요청 한도에 도달했는지 확인
도달 했다면 요청 거부
도달 하지 않았다면 api 서버로 요청 전달
미들웨어는 카운터 값을 증가 한 다음에 레디스에 다시 저장
3. 상세 설계
처리율 제한 규칙?
처리가 제한된 요청들은 어떻게 처리됨?
처리율 한도 초과 트래픽은 어떻게 처리되는가?
429 응답을 보내는데,
HTTP 헤더에 특정 값과 같이 보낼 수 있음.
X-Ratelimit-Remaining: 윈도 내 에 남은 처리 가능 요청 의 수
X-Ratelimit-Limit: 매 윈도마다 클라이 언트가 전송할 수 있는 요청 의 수
X-Ratelimit-Retry-After: 한도 제한에 걸리지 않으려면 몇 초 뒤에 요청을 다시 보내야 하는지 알림
![[Pasted image 20250727151459.png]]
429 응답을 보낼때도 2가지 옵션
요청을 버리거나?
혹은 해당 옵션을 메세지 큐에 보관 -> 나중에 처리..하는 방법도 있을듯?
분산 환경에서의 처리율 제한 장치의 구현
분산 환경에서는 문제가 있음.
경쟁 조건(race condition)
동기화 (synchronization)
경쟁 조건
![[Pasted image 20250727151718.png]]
락을 사용할 수 있겠지만, 성능에 이슈 있음.
해결할 수 있는 방법?
Lua script
레디스가 단일 트랜잭션으로 실행하는 것을 보장하는 것.
트랜잭션 실행하는 동안, 다른 클라이언트 명령이 중간에 끼어들 수 없음.
sorted set
슬라이딩 윈도우 로그 알고리즘을 구현함
이걸 루아 스크립트로 묶으면 경쟁조건을 완벽하게 해결할 수 있음.
-- KEYS[1]: ratelimit 키 (예: "ratelimit:user123")
-- ARGV[1]: 현재 시간 (타임스탬프)
-- ARGV[2]: 윈도우 크기 (예: 60000)
-- ARGV[3]: 최대 허용량 (예: 5)
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])
-- 1단계: 윈도우 바깥의 오래된 기록 삭제
local clear_before = now - window
redis.call('ZREMRANGEBYSCORE', key, '-inf', clear_before)
-- 2단계: 현재 윈도우 내의 요청 수 확인
local count = redis.call('ZCARD', key)
-- 3단계: 허용 여부 결정
if count < limit then
-- 허용: 현재 요청을 기록에 추가
redis.call('ZADD', key, now, now)
-- TTL(만료 시간)을 설정하여 메모리 관리
redis.call('EXPIRE', key, window / 1000) -- 초 단위로 설정
return 1 -- 성공
else
return 0 -- 실패
end
동기화 이슈
처리율 제한 장치 서버를 여러대 두개 되면 동기화가 필요해질 수 있음.
예시
동시 읽기: 서버 A와 서버 B가 거의 동시에 Redis에서 카운터 값 9를 읽습니다.
잘못된 판단:
서버 A는
9 < 10
이므로 요청을 허용하기로 결정합니다.서버 B도
9 < 10
이므로 요청을 허용하기로 결정합니다.
덮어쓰기:
서버 A가 카운터를 10으로 업데이트합니다.
거의 직후에 서버 B도 카운터를 10으로 업데이트합니다.
결과:
실제로는 11개의 요청이 시스템에 들어왔지만, 카운터에는 10이라고 기록됩니다.
이렇게 제한이 뚫리는 것이 바로 동기화 이슈입니다.
어떻게 해결?
읽고 수정하고 쓰는 것을 단일 작업으로 만듬 -> Redis lua script
![[Pasted image 20250727152855.png]]
성능 최적화
지연 시간 이슈
최종 일관성
모니터링
선택한 처리율 제한 규칙이 너무 빡빡하다면, 많은 유효한 요청이 처리되지 못하고 버려질 것.
그러면 규칙을 완화해야함
4. 마무리
처리율 제한 알고리즘
토큰버킷
티켓 발급기
요청이 없을 때는 토큰이 버킷에 쌓임. 갑자기 요청이 몰려와도 쌓아둔 요청 만큼 토큰을 빠르게 처리 가능
누출버킷
바닥에 작은 구멍이 뚫린 물통
물통의 크기와 상관 없이 물은 바닥의 구멍을 통해 항상 일정한 속도로 빠져나감
고정된 속도로 요청을 꾸준히 처리
고정 윈도 카운터
매시간 정각에 리셋되는 출입 게이트
1시 59분 100명, 2시 00분 100명 들어오면 순가적으로 200명 요청이 처리될 수 있음.
이동 윈도 로그
CCTV 녹화 기록을 돌려보는 것
모든 사람의 출입 시간을 초 단위로 기록
처리율을 아주 정확하게 제한할 수 있음.
모든 요청 시간을 저장해야하므로 메모리 사용 크다
이동 윈도 카운터
이전 시간대의 입장객 수를 참고하는 똑똑한 게이트
고정 윈도우 카운터 + 이동 윈도 로그 의 장점만 합침
경성, 연성 처리율 제한
경성 -> hard, 요청 의 갯수는 임계치를 절대 넘어설 수 없음
연성 -> soft, 요청 개수는 잠시 동안 임계치를 넘어설 수 있음.
다양한 계층
Last updated
Was this helpful?