앞 단계에서 고정 윈도우가 경계에서 두 배를 통과시키는 것을 봤습니다. 원인은 자르는 기준이 고정된 시각이라는 것이었습니다. 기준을 요청 시점으로 바꾸면 경계가 사라집니다.
통과한 요청의 시각을 모아 둔다
판정은 두 단계입니다. 60초보다 오래된 항목을 버리고, 남은 개수를 한도와 비교합니다. 언제 보든 뒤로 60초를 보므로 경계 버스트가 원리적으로 없습니다.
비용은 들고 있는 양이다
한 키가 들고 있는 항목은 최대 한도만큼입니다. 한도가 분당 1,000회 이면 키마다 최대 1,000개입니다.
| 활성 키 | 최대 항목 수 |
|---|---|
| 1,000개 | 100만 |
| 10만 개 | 1억 |
항목 하나가 수십 바이트라도 1억 개면 수 기가바이트입니다. 그리고 이 메모리는 한도를 다 쓰는 키가 많을수록 늘어납니다.
거절한 요청은 저장하지 않는다
한도를 넘어 거절한 요청까지 저장하면 이상한 일이 생깁니다. 한도를 넘긴 뒤에도 계속 요청을 보내는 쪽이 저장소를 계속 키웁니다. 막으려던 상대가 비용을 늘리는 구조가 됩니다.
통과시킨 요청만 기록한다
거절은 세지 않고 응답만 돌려준다
이 규칙은 남용을 막는 장치에서 일반적으로 성립합니다. 거절 자체가 비싸면 거절이 공격 수단이 됩니다.
판정 비용도 요청마다 든다
버리기와 세기가 매 요청에 붙습니다. 피크 초당 5만 요청이면 그만큼 반복됩니다. 저장소가 정렬된 집합을 다뤄 준다면 한 번에 처리할 수 있지만, 버릴 항목이 많이 쌓인 키에서는 그 한 번이 길어집니다.
1ms 예산에서 이 방식은 여유가 없습니다. 그래서 선택은 둘 중 하나입니다.
| 선택 | 언제 |
|---|---|
| 이 방식을 쓴다 | 키 수가 적고 정확도가 돈과 직결될 때. 유료 호출 과금 경계 등 |
| 더 값싼 근사로 간다 | 키가 많고 오차가 허용될 때. 이 요구사항이 그렇다 |
정확한 방법이 늘 정답은 아니다
이 방식은 오차가 0입니다. 그런데 요구사항은 오차 5퍼센트 를 허용한다고 적었습니다. 허용된 오차를 쓰지 않으면 그만큼을 비용으로 내는 것입니다.
요구사항에 적힌 여유는 쓰라고 있는 것입니다. 정확도를 공짜로 얻을 수 있을 때만 정확한 쪽을 고릅니다.