대규모시스템설계기초 ch4
대규모 시스템 설계 기초 ch4. 처리율 제한 장치의 설계
- API 처리율 제한 장치 장점
- DoS 공격에 의한 자원 고갈 방지 가능
- 추가 요청 처리에 대한 비용 절감
- 서버 과부하를 막음
- 1단계. 문제 이해 및 설계 범위 확정
- 시스템의 요구사항을 정확히 파악해야 한다.
- 서버측 제한 vs 클라이언트 측 제한
- IP주소 기반 제한 vs 사용자 ID 기반 제한
- 시스템 규모의 정도
- 분산 환경의 유무
- 독립된 장치 vs 어플리케이션에 녹여야 함
- 2단계. 개략적 설계안 제시 및 동의 구하기
- 처리율 제한 장치는 보통 API 게이트웨이라 불리는 컴포넌트에 구현됨
- API 게이트웨이에서 처리율 제한, SSL 종단, 사용자 인증, IP 허용 목록 관리 등 제공
- 정답은 없으니, 현재 기술 스택에서 녹일 수 있는 것 고민할 것
- 프로그래밍 언어, 캐시 서비스 등 현 기술 스택
- 사업 필요에 알맞는 처리율 제한 알고리즘 고려
- 시간/인력이 모자라면 상용 API 게이트웨이 도입을 고려
- 처리율 제한 알고리즘
- 토큰 버킷 알고리즘
- 사전 설정된 양의 토큰이 주기적으로 채워짐
- 요청 도착시 버킷에 충분한 토큰 있는지 검사하고, 있다면 처리/없다면 요청 버림
- API 엔드포인트 * 사용자 or IP 별로 별도의 버킷을 둠
- 처리율을 공통적으로 초당 몇개로 제한하고자 한다면, 버킷을 한개로 공유하는 것도 방법
- 누출 버킷 알고리즘
- FIFO로 구현
- 요청 도착하면 큐가 가득 차 있는지 봄. 빈자리 있으면 큐에 넣음/없다면 요청 버림
- 버킷 크기/처리율 산정을 잘 해야함
- 장점
- 큐의 크기 제한 -> 메모리 사용량 예측 가능
- 고정된 처리율 -> 안정된 출력
- 단점
- 단기간 많은 트래픽 -> 오래된 요청 쌓임 -> 제때 처리못하면 최신 요청 버림
- 버킷 크기/처리율 산정 잘못하면 망가짐
- 고정 윈도 카운터 알고리즘
- 타임라인을 고정된 윈도우로 나누고, 윈도우마다 카운터 붙임
- 요청 들어올 때마다 카운터 +1
- 카운터 임계치에 도달하면, 새 요청은 새 윈도우 열릴때까지 버려짐
- 장점
- 메모리 효율 좋음. 이해도 쉬움.
- 특정한 트래픽 패턴 처리하기 용이
- 단점
- 특정 경계 시간에 과다 트래픽 처리 가능 (ex. 1분 카운터라면, 2:01:30 ~ 2:02:30 에 기존 1분 처리량보다 많은 양 처리 될 수 있음)
- 이동 윈도 로깅 알고리즘
- 윈도우 위와 같으나, 거부된 timestamp도 저장하여 계산에 사용. (윈도우 측정용)
- 장점
- 매우 정교함. 허용되는 요청의 갯수가 시스템 처리율 한도를 안넘김
- 단점
- 거부된 건의 timestamp도 저장하다보니, 다량의 메모리 사용.
- 이동 윈도 카운터 알고리즘
- 이전 시간대의 비율을 산정하여 현재 시간에 처리된 건 count
- ex. 현재 1분간의 요청 수 + (직전 1분간의 요청 수 * 이동 윈도와 직전 1분이 겹치는 비율)
- 장점
- 이전 시간대의 평균 처리율에 따라 현재 윈도 계산. 짧은 시간 몰리는 트래픽에도 대응 가능
- 메모리 효율 좋음
- 단점
- 다소 느슨한 추정치. 하지만 크게 벗어나진 않음
- 계략적인 아키텍처
- 카운터 어디에 보관할래? -> Redis 사용 추천. INCR/SETEX 등 사용해보자.
- 3단계. 상세 설계
- 처리율 제한 규칙
- 처리율 한도 초과 트래픽 처리
- HTTP 429 (too many requests) 로 응답
- 메시지 나중에 처리하기 위해 큐에 보관도 가능 (DLX 감성?)
- 헤더에 처리율 제한 때매 못 처리했다고 응답
- X-Ratelimit-Remaining, X-Ratelimit-Limit, X-Ratelimit-Retry-After
- 상세 설계
- Rate Limiter의 분산환경 내 구현
- Race Condition
- lock으로 해결 가능.
- 다만 이는 성능 떨어뜨림. 하기 다른 방법으로 해결 가능
- 동기화 이슈
- 고정 세션 (근데 확장성이 좀 떨어짐)
- 레디스와 같은 중앙 집중형 데이터 저장소
- 성능 최적화
- 마무리
- hard/soft 처리율 제한: 임계치 넘어서는 것 어느 수준으로 제어?
- OSI 계층별 처리율 제한
- 처리율 제한 회피 방법 (클라 설계)
- 클라 캐시 도입 -> API 호출 줄임
- 너무 많은 요청 보내지 않도록 수정
- gracefully 복구
- retry 로직 구현시에는 충분한 back-off
스터디
- 실제로 어뷰저한테 딱 rate limit 넘은 것을 알려주면 오히려 안좋을 수 있다. (여기까지가 limit 이구나!)
- 특정 부서에서는 직접 구현해서 사용 (고정 크기 윈도우)
- 클라에서 rateLimit을 두는 방법: 열심히 스티커 누르고, 이를 다 서버 API 호출로 처리하면 안됨. 스티커 누른거 멈추면 그 쪽수만큼 API 호출
- 서비스에서 실제로 어떻게 쓰이는지는 오픈하고 추이를 통해 확인해봐야 하는 것들도 많다
- rateLimit은 부가적인 기능이라, 도메인에 문제가 발생하면 안된다
- rateLimit 모니터링 잘 하고있는가?
- retry 로직 back-off 시간은 지수적으로