속도 제한에 대한 대안 (새 탭에서 열림)
Figma는 스팸 공격으로부터 서비스를 보호하기 위해 Redis 기반의 자체 레이트 리미터를 구축했다. 토큰 버킷과 고정 윈도 카운터는 메모리 효율이 좋지만 정확성이나 동시성 문제가 있었고, 슬라이딩 윈도 로그는 정확하지만 메모리를 많이 사용한다. Figma는 여러 기법을 조합해 분산 환경에서 빠르고 정확하며 메모리 효율적인 방식으로 요청량을 제한했다. ## 레이트 리미팅의 요구사항 - 사용자나 IP 주소별로 일정 시간 동안 허용할 요청 수를 제한한다. - 예: 1분에 25회 요청 허용 - 여러 웹 서버가 동일한 제한 정보를 공유해야 하므로 외부 저장소가 필요하다. - 웹 요청 처리 속도를 크게 저하시켜서는 안 된다. - 오래된 추적 데이터를 효율적으로 삭제해야 한다. - 과도한 요청을 정확하게 차단하면서 메모리 사용량도 최소화해야 한다. - Figma는 PostgreSQL보다 읽기·쓰기 속도가 빠르고 만료 키를 지원하는 Redis를 추적 데이터 저장소로 선택했다. ## 토큰 버킷의 장점과 동시성 문제 - 사용자마다 다음 두 값을 Redis 해시에 저장한다. - 마지막 요청 시각 - 현재 남아 있는 토큰 수 - 시간이 지나면 설정된 보충 속도에 따라 토큰을 다시 채운다. - 토큰이 0개가 되면 요청을 제한한다. - 장점: - 구현 개념이 단순하다. - 사용자별로 작은 해시 하나만 저장하므로 메모리 효율이 높다. - 일정한 요청 속도와 일시적인 버스트를 모두 처리할 수 있다. - 문제점: - Redis에서 값을 읽고 계산한 뒤 다시 쓰는 과정이 원자적이지 않다. - 두 서버가 동시에 같은 토큰 수를 읽으면, 둘 다 요청을 허용하는 경쟁 조건이 발생할 수 있다. - 결과적으로 실제 허용량보다 많은 요청이 통과할 수 있다. - Redis 락이나 Lua 스크립트로 원자성을 보장할 수 있지만, 락은 지연과 복잡성을 늘리고 Lua는 코드베이스에 별도 언어를 추가해야 한다. ## 고정 윈도 카운터의 단순성과 경계 문제 - 요청이 발생한 시간 구간을 키로 삼아 Redis 카운터를 증가시킨다. - 예: `user:1:2017-03-30T10:00`에 해당 분의 요청 수 저장 - 카운터가 제한값을 넘으면 요청을 거부한다. - 각 키에 만료 시간을 설정해 오래된 카운터를 자동 삭제한다. - `INCR` 같은 Redis 연산을 사용하므로 토큰 버킷보다 동시성 처리가 안전하다. - 메모리 사용량도 적고 구현과 동작을 이해하기 쉽다. - 하지만 윈도 경계에서 허용량보다 최대 두 배 많은 요청이 통과할 수 있다. - 예를 들어 분당 5회 제한에서 10:00:59에 5회, 10:01:00에 다시 5회를 보내면 실제로는 2초 안에 10회가 허용된다. - 따라서 고정 윈도만으로는 요청량을 정확하게 제한하기 어렵다. ## 슬라이딩 윈도 로그의 정확성과 메모리 비용 - 각 요청의 정확한 타임스탬프를 저장한다. - 새 요청이 들어오면 제한 시간보다 오래된 기록을 삭제하고, 현재 윈도 안의 요청 수를 계산한다. - 윈도가 계속 이동하므로 고정 윈도 경계에서 발생하는 폭주 문제가 없다. - 가장 정확한 방식이지만 모든 요청 기록을 보관해야 한다. - 요청 빈도가 높은 사용자나 공격자가 많아지면 저장해야 할 타임스탬프 수가 급증한다. - 따라서 정확성은 높지만 Redis 메모리를 많이 사용한다. ## Figma의 절충 방식 - Figma는 고정 윈도 카운터의 낮은 메모리 사용량과 슬라이딩 윈도의 정확성을 결합하는 방식을 사용했다. - 전체 제한 구간을 더 작은 시간 단위의 카운터들로 나누고, 현재 구간과 직전 구간의 요청량을 이용해 이동 중인 윈도의 사용량을 계산한다. - 개별 요청의 타임스탬프를 모두 저장하지 않고 카운터만 유지하므로 슬라이딩 윈도 로그보다 메모리 효율적이다. - Redis의 원자적 카운터 증가 연산을 활용해 여러 애플리케이션 서버가 동시에 요청을 처리해도 경쟁 조건을 줄일 수 있다. - Redis 키에 만료 시간을 지정해 오래된 시간 구간의 데이터가 자동으로 제거되도록 한다. - 이 방식은 완벽한 요청 단위 정확성보다는 약간의 근사치를 허용하는 대신, 다음 특성을 균형 있게 제공한다. - 분산 환경에서의 안전성 - 낮은 지연 시간 - 적은 메모리 사용량 - 고정 윈도보다 나은 제한 정확도 ## 스팸 공격 방어 효과 - 공격자는 다수의 이메일 주소로 문서 초대 요청을 반복해서 보냈다. - 레이트 리미터가 비정상적인 요청 증가를 조기에 감지해 추가 요청을 차단했다. - 그 결과 이메일 발송 비용의 급증과 발신자 평판 하락을 막을 수 있었다. - 레이트 리미팅은 단순한 성능 보호 장치뿐 아니라 이메일 초대, 비밀번호 재설정, 결제 등 악용되기 쉬운 기능의 스팸 방어 수단으로도 활용할 수 있다. 서비스 규모가 크고 여러 서버가 요청을 처리한다면 Redis 기반의 원자적 카운터와 만료 키를 우선 고려하는 것이 실용적이다. 높은 정확성이 필요하면 슬라이딩 윈도 로그를, 메모리와 성능을 중시하면 슬라이딩 윈도 카운터나 세분화된 고정 윈도 방식을 선택하는 것이 적절하다.