웹 아키텍쳐

웹 아키텍처16 - 파이썬으로 배포할 때 알고있어야 하는 Gunicorn(WSGI)

dodo4723 2024. 2. 17. 10:04
728x90
반응형

제 프로젝트는 사용자가 특정 차트를 고르면, 코스피 코스닥 전 종목의 과거(5년) 차트들을 모두 탐색하여 가장 유사한 차트 10개 정도를 골라 사용자에게 보여주는 것이 목표입니다.

 

비슷한 차트 검색기

 

 

비슷한 차트 검색기

전 종목의 최근 10년간 모든 차트를 탐색합니다. 내 종목의 차트는 과연 상승하는 차트일까요?

www.similarchart.com



 

챗GPT : Flask는 그렇게 막 배포하면 안 돼

 

저는 웹 프로젝트에 Flask를 사용하고 있습니다. Flask는 간단한 웹 사이트, 혹은 간단한 API 서버를 만드는 데에 특화되어있는 Python Web Framework입니다.

 

하지만 실제 production 환경에서 Flask 애플리케이션을 배포할 때는, Flask의 개발 서버를 사용하는 것이 아니라, 좀 더 강력하고 안정적인 WSGI(HTTP Web Server Gateway Interface) 서버가 필요합니다. 여기서 Gunicorn의 역할이 시작됩니다.

 

저는 Flask의 멀티스레드와 동시성에 관해 챗 GPT에게 이것저것 물어보다가 우연히 gunicorn의 존재를 알게 되었습니다.

 

 

WSGI(WebSever Gateway Interface)란?

파이썬 애플리케이션이 웹서버와 통신하기 위한 인터페이스로 웹서버의 요청을 해석을 해서 파이썬 애플리케이션에게 전달해 줍니다. 대표적으로 gunicornuWSGI가 있습니다. 이 중에서 제 프로젝트에는 더 가볍다고 알려진 gunicorn을 사용 중이니 gunicorn에 대해서 더 자세하게 알아보겠습니다.

 

 

Gunicorn이란?

Gunicorn은 Green Unicorn의 줄임말로, UNIX 시스템에서 작동하는 Python WSGI HTTP 서버입니다. Gunicorn은 pre-fork worker 모델을 사용하며, 이는 주 프로세스가 여러 worker 프로세스를 관리하고, 각 worker가 개별 요청을 독립적으로 처리할 수 있도록 함으로써 높은 동시성과 빠른 응답 시간을 제공합니다.

 

 

Gunicorn의 주요 특징

간편한 배포 : Gunicorn은 설정이 간단하며 Flask 애플리케이션과의 통합이 용이합니다.

확장성 : Worker 프로세스의 숫자를 조정하여 애플리케이션의 부하에 맞게 확장할 수 있습니다.

호환성 : 여러 가지 WSGI 애플리케이션과 호환되며, Django와 같은 다른 웹 프레임워크와도 잘 작동합니다.

성능 : 여러 worker를 관리함으로써 고성능을 유지할 수 있습니다.

 

 

Gunicorn의 작동 원리

Gunicorn은 master process와 여러 worker process로 구성됩니다. Master process는 애플리케이션을 로드하고, 설정된 수의 worker process를 생성합니다. 각 worker는 독립적으로 요청을 받아 처리하며, 이는 Gunicorn이 동시에 여러 요청을 처리할 수 있게 만들어 줍니다.

 

 

Gunicorn을 사용할 때의 모범 사례

Worker 수 조정 : CPU의 코어 수와 I/O 특성에 맞게 worker 수를 조정하는 것이 중요합니다.
타임아웃 설정 : 네트워크 지연이나 복잡한 요청 처리로 인해 발생할 수 있는 문제를 방지하기 위해 적절한 타임아웃 값을 설정해야 합니다.
로깅 : 오류 추적과 모니터링을 위해 로깅을 설정하고 로그를 주기적으로 검토해야 합니다.
보안 : HTTPS와 같은 보안 프로토콜을 사용하고, 필요한 경우 Gunicorn을 웹 서버 뒤에 배치하여 추가 보안 계층을 제공합니다.

 

 

Worker 프로세스의 비정상적 종료

Gunicorn에서 worker 프로세스가 비정상적으로 종료되는 주된 이유는 다음과 같습니다.

메모리 부족 (Out of Memory, OOM) : 특정 프로세스가 사용 가능한 메모리를 모두 소비했을 때, 운영 체제는 자원을 확보하기 위해 해당 프로세스에 SIGKILL 신호를 보내 종료시킬 수 있습니다.
버그나 예외 상황 : 프로그램 내부의 버그나 처리되지 않은 예외로 인해 프로세스가 충돌할 수 있습니다.
자원의 과다한 사용 : 파일 핸들러의 과도한 사용이나 네트워크 연결 문제 등으로 인해 발생할 수 있습니다.

[CRITICAL] WORKER TIMEOUT (pid:7)
[ERROR] Worker (pid:27) was sent SIGKILL! Perhaps out of memory?

 

제 프로젝트에서는 위와 같이 출력되며 프로세스가 재시작되는 경우가 잦습니다. 제 프로젝트에는 matplotlib 라이브러리로 이미지를 그리는 부분이 있는데, 이때 해결하기가 힘든 메모리 누수가 발생합니다. 이렇게 메모리 누수가 발생하면 gunicorn은 SIGKILL을 보내어 자동으로 프로세스를 재시작하는 것 같습니다.

 

하지만 프로세스를 재시작하는 과정에서 응답시간이 더 소요되기 때문에, 근본적인 메모리 누수 문제를 해결할 수 있으면 좋겠네요.

반응형