운영중인 장고 + 지유니콘 백엔드 메모리 누수 문제 해결 production django + gunicorn backend memory leak fix (feat uwsgi)
필자는 회사에서 django+gunicorn 스택으로 백앤드를 다루고 있다.
이전에는 django+uwsgi를 사용하였으나, 메모리를 구글 크롬 브라우저급으로 먹어대는 uwsgi 녀석을 더이상 사용하지않고… gunicorn으로 서비스를 운영하기 시작했다.(예전글 python개발자 uwsgi를 버리고 gunicorn으로 갈아타다)
팀의 동료로부터 django+gunicorn 백앤드 서비스의 memory 사용량이 시간이 지남에따라 점점 늘고 있다고 전달을 받았고, 관리자 툴을 이용해서 확인해본 결과 위와 같은 그래프의 모양으로 메모리가 점점 증가 하고 있다는 것을 확인했다.
짐작으로는 django + gunicorn + supervisor
로 사용을 하고 있는데gunicorn
설정중에서 max-requests
가 세팅이 되어있지 않았고 그로인해서 메모리 누수가 발생했을 것이라 예상하였다.
(max-request
설정을 해주지 않는다면 worker
가 리스타트를 하지않는 문제가 발생한다)
Gunicorn 에서는 max-requests
라는 기능을 제공한다.
명시적으로 특정 requests만큼의 요청을 받은 후 worker가 자연스럽게 restart를 해주는 기능이다. 이 기능을 통해서 worker가 물고있던(?) 메모리를 릴리즈해주게된다. 또 max-requests-jitter
이라는 기능이 있는데, 모든 worker가 restart 가 되어 다운타임이 상황이 발생해 장애로 이어질수가 있는데 jitter라는 명령어로 이 상황을 회피할 수 있다.
## supervisor.conf 또는 gunicorn 배포 스크립트에 아래와같이 추가를 해준다.
gunicorn --max-requests 1000 --max-requests-jitter 50 ... myapp.wsgi
메모리 사용량이 조금씩 조금씩 점진적으로 증가하고있던 녹색 면적에 비해서 수정 배포후 달라진 모습을 볼 수 있다. ( 뭔가 메모리 사용량이 급증하는 것 처럼보이나 몇분 후에 다시 제자리로 돌아오는 모습을 확인 할 수 있었다.
uwsgi
도 비슷한 방법으로max-requests
를 설정하거나max-requests-delta
를 설정하여 메모리 누수를 방지할수 있다.
하지만 필자는 uwsgi를 사용하는 것을 권장하지않는다.
참조: https://adamj.eu/tech/2019/09/19/working-around-memory-leaks-in-your-django-app/