이번에 톡사원증이 오픈을 하게 되었다.
톡사원증은 특정 증명서 발급을 통해 회사 이력을 카드로 인증해주는 서비스이다.
요 기쁜 소식을 사내에 오픈 공지를 올렸을때, 순간적으로 트래픽이 살짝 높아지게 되었는데, 이때 증명서 발급 신청 건이 우수수 실패가 되었다.
맙소사… 아직 대외로 오픈소식을 알리기도 전인데 이게 왠 날벼락인가…
이대로라면 프로모션시에 큰 장애가 날 듯 싶어 급하게 rate limiter 를 개발하게 되었다.
rate limit 를 구현하는 방법은 다양하다.
nginx에서 사용자 IP 별 요청을 제한하거나 어플리케이션 단에서 queue를 이용하는 방법, 또는 redis 를 이용하는 방법 등 여러가지 방법이 있는데, 이중 최대한 쉽게 구현할 수 있는 redis 를 사용하기로 했다. (예시도 많고..)
그리고 방법은 2가지를 정할 수 있는데,
ts = CURRENT_UNIX_TIME()
keyname = key+":"+ts
MULTI
INCR(keyname)
EXPIRE(keyname,10)
EXEC
current = RESPONSE_OF_INCR_WITHIN_MULTI
IF current > 100 THEN
ERROR "too many requests per second"
ELSE
PERFORM_API_CALL()
ENDcurrent = 0
MULTI
ZREMRANGEBYSCORE $key 0 ($currentTime - $slidingwindow)
current = ZRANGE $key 0 -1
EXEC
IF current > 100 THEN
ERROR "too many requests per second"
ELSE
PERFORM_API_CALL()
MULTI
ZADD $key $currentTime
EXPIRE $key $slidingwindow
EXEC이때, ZREMRANGEBYSCORE 명령어와 ZADD 명령어는 한 트랜잭션에 존재하지 않기 때문에 정말 짧은 순간에 트래픽이 몰렸을 경우, 방어가 되지 않는 문제가 생긴다.
각 단점을 다시 정리하면,
하지만 전자증명서 서비스 특성상, 정말 짧은시간에 burst traffic이 발생할 확률보단 정해진 시간에 burst traffic 이 발생할 확률이 높아 두번째 방법을 선택하게 되었다.
아직 개발 전이지만.. 시간이 너무 촉박하다ㅠㅜ 어휴