글 작성 시점은 incoming webhook 제공을 위해 개발 중이며(4일차)
백엔드는 거의 다 틀을 잡아 놨기 때문에 개발 하면서 사용한 ratelimit 에 대해 이야기 하려고 한다.
(웹훅 개발이 끝나고 배포 나가면 기록을 남길 예정)
외부에 서비스를 제공해야 되므로 rate limit 이 존재 해야 될 것 같고
특히, 예를 들어 60 requests per minute 그리고 ip 이런 조건들을 생각했어야 했기 때문에
괜찮은 방법이 없는지 생각을 많이 했던 것 같다.
물론, 이제 갓 2년차인 개발자인 내가.. 개발하면서 고민하고 걱정하는 부분들은
이미 누군가가 고민을 했고, 개발을 했고, 오픈 되어 있다.
Python 으로 요청을 받을지 Go 언어로 요청을 받을지 고민을 해보고..
Python을 선택했고, ratelimit 을 다뤄주는 django-ratelimit 을 사용하기로 결정.
django-ratelimit document
사용법은 간단하다.
저런식으로 decorator 만 사용해주면 된다.
그리고 최신버전에서는 middleware 방식도 있다.
본인은 decorator 방식으로 구현했고, @ratelimit decorator의 옵션이 더 있나 궁금해서 라이브러리를
살펴 보니까
def ratelimit(group=None, key=None, rate=None, method=ALL, block=False):
def decorator(fn):
@wraps(fn)
def _wrapped(request, *args, **kw):
old_limited = getattr(request, 'limited', False)
ratelimited = is_ratelimited(request=request, group=group, fn=fn,
key=key, rate=rate, method=method,
increment=True)
request.limited = ratelimited or old_limited
if ratelimited and block:
raise Ratelimited()
return fn(request, *args, **kw)
return _wrapped
return decorator
이런식으로 되어있었다.
살펴보니 사용방법은 알았고 어떤식으로 사용했냐면
@ratelimit(key='ip', rate='60/m', method='POST')
def 함수명:
...
was_limited = getattr(request, 'limited', False)
if was_limited:
```
...
...
```
return response
...
block=True 옵션까지 주면 원하는 라이브러리 안에서 raise Ratelimited() 가 일어난다.
그래서 block 은 dafalut 값인 False 로 처리하고
1분안에 같은 ip로 200 회의 POST 요청이 들어올 때
getattr(request, 'limited') 값이 True 가 되어
밑에서 원하는 response 값으로 돌려주면 된다.
참고로 너무 많은 요청 횟수의 http 상태값은 429 ( HTTP 429 )
방법도 간단하고 좋은 것 같다.
또한 테스트도 해보았기 때문에 만족스럽다.
이렇게 ratelimit 에 대해 생각 할 수 있는 기회가 있어 좋았고..
항상 느끼는거지만 보고 생각하는것도 중요하지만 직접 해보지 않고 눈, 머리로.. 추천하지 않는다.
어느정도라도 직접 해 봐야한다. 왜냐하면 그 안에서의 시행 착오 축적이 없기 때문에..
여튼.. 끝 !
(혹시 더 좋은방법, 더 좋은 라이브러리가 있으면 추천 부탁드리겠습니당)
'Framework > Django' 카테고리의 다른 글
[Django] models cached_property decorator (0) | 2022.02.23 |
---|---|
[Django] models property decorator (@property) (0) | 2022.02.23 |
[Django] auto_now , auto_now_add (0) | 2022.02.11 |
[Django] You are trying to add the field '필드명' ... (auto_now_add) (0) | 2022.02.11 |
[DRF] JWT (simple jwt) (2) | 2022.01.26 |