API 요청 제한(Rate Limit) 설계 면접: 한 계정이 초당 백 번 부르면
시스템 디자인 Vol.1 · 18장 「같은 사람이 초당 백 번 부릅니다」에서
이런 화면입니다
쿠폰 목록 API가 갑자기 느려졌습니다. 로그를 보니 한 계정이 초당 백 번 넘게 부르고 있습니다. 앱의 화면 하나가 스크롤할 때마다 부르도록 잘못 만들어져 있었습니다.
그날 밤에는 다른 계정이 로그인 API를 몇 분 동안 수만 번 부릅니다. 이번에는 공격입니다. 실수와 공격이 같은 모양으로 들어옵니다.
면접관이 이렇게 묻습니다
한 계정이 API를 초당 백 번 부릅니다. 어떻게 막으시겠습니까.
범위부터 좁힙니다
먼저 무엇으로 셀지 묻습니다. 로그인 API처럼 아직 회원 번호가 없는 요청도 있고, 쿠폰 목록처럼 로그인한 손님만 부르는 요청도 있습니다.
그다음 문턱을 묻습니다. 몇 번에서 막을지, 그 숫자를 무엇을 근거로 정할지에 따라 먼저 걸리는 사람이 달라집니다.
세는 기술은 어렵지 않습니다. 누구를 무엇으로 셀지, 문턱을 어디에 둘지가 이 문제의 핵심 질문입니다.
가장 많이 나오는 답
근거 없이 「초당 열 번」 문턱 하나를 정해 서비스 전체에 겁니다. 넘으면 실패를 돌려줍니다.
if (count(userId, 1s) > 10) {
return 429; // 끝
}
부하 테스트로 초당 백 번을 쏘면 확실히 막힙니다.
그런데 여기서 깨집니다
근거 없이 정한 문턱 하나에 화면을 빠르게 넘기는 성실한 손님이 먼저 걸립니다. 밤마다 도는 배치 작업이 같은 API를 부르다 걸리는 것은 배포한 뒤에야 압니다.
막힌 앱이 무엇을 받는지 정해 두지 않으면, 앱은 즉시 다시 부릅니다. 막으려던 요청이 오히려 늘어납니다.
떨어지는 답은 이런 모양입니다
- 「초당 열 번으로 막습니다」로 끝내고, 그 숫자의 근거를 답하지 못합니다.
- 막힌 쪽은 그냥 실패하게 둡니다.
- 배치 작업이 걸리는 것을 배포한 뒤에 압니다.
면접관은 여기서 멈추지 않습니다
막힌 앱이 바로 다시 부르면요?
막는 쪽이 요청을 오히려 늘리는 구조를 아는지 봅니다.
로그인 API는 회원 번호가 없는데 무엇으로 세나요?
회원 번호가 없는 요청을 어떻게 다룰지 생각했는지 봅니다.
세는 방법 세 가지는 서로 무엇이 다른가요?
세 방법을 무엇으로 비교할지 스스로 기준을 세우는지 봅니다.
이 다음 판단은 책에서 이어집니다
책은 세는 방법 셋을 비교해 하나를 고르고, 그 값이 놓이는 자리를 정한 뒤, 막힌 쪽이 무엇을 받는지까지 풉니다.
18장에서 이어지는 것
- 세는 방법 셋과 그 차이
- 세는 값을 두는 자리
- 막힌 쪽이 받는 것
- 이 장이 만든 테이블을 행으로 읽어 보기