본 글에서는 Django를 실제 서버로 배포하면서 필요했던 Nginx, Gunicorn의 개념에 대해 알아보고자 합니다.
참고로 저는 Django로 백엔드를 구축했다 보니 아래에서 소개되는 웹서비스 구조는 Django를 중심으로 한 것임을 미리 알려드립니다. 특히 WAS에 대한 정의가 스프링의 경우 톰캣이라고 알려져 있지만 다른 진영(Django, .NET 등)에선 딱히 뭐다라고 정의되지 않는다고 하네요.
웹서버와 WAS
결론적으로 Nginx는 웹서버(Web Server)이고, 또 다른 웹서버로는 그 유명한 Apache도 있죠. 웹서버는 클라이언트가 (웹사이트에서) 무언가 요청하면 그에 대한 적절한 반응을 해주는 존재라고 생각하면 됩니다. 이런 웹서버와 항상 같이 등장하는 개념이 WAS(Web Application Server)입니다. 웹서버와 WAS는 비슷해 보이지만 약간의 차이가 있는데 일단 아래 그림을 봅시다.
웹서버는 단순히 정적 파일(static file)을 응답하는 존재라면, WAS는 동적 사이트를 전문적으로 처리하는 존재입니다. 정적 파일은 말 그대로 멈춰있는 파일, 즉 이미지, html, css 등 변하지 않는 파일 그 자체를 가리키는 것입니다. 반면, 동적인 처리는 클라이언트가 아이디, 패스워드를 넘겼을 때 하는 로그인 처리 또는 클라이언트 쿼리 파라미터에 따라 달라지는 DB 값 표시 등을 말합니다.
웹서버를 별도로 운영하는 이유
웹서버를 별도로 운영하는 이유는 WAS의 부담을 줄여주기 위함입니다. 생각해보면 이미지, html, css 등 웹 사이트 운영을 함에 있어서 기본적으로 변하지 않는 파일들은 굳이 동적인 처리를 하는 WAS에서 담당할 필요가 없겠죠. 다시 말해 클라이언트의 요청 중 웹서버가 처리할 수 있다면 WAS까지 굳이 전달하지 않으면서 WAS의 업무 비중을 줄여주는 것입니다.
많은 웹서버 중에서도 Nginx를 사용하는 이유는 다음과 같습니다.
1. 빠른 속도
- 동시요청(concurrent connections)이 많아도 메모리 사용량이 현저히 적음
- 초당 처리 요청 역시 많음
2. 리버스 프록시(Reverse proxy)로 사용 가능
- 리버스 프록시란 인터넷과 백엔드 사이에 있는 서버를 가리킴(포워드 프록시는 클라이언트와 인터넷 사이)
- 여러 WAS가 존재하면 클라이언트 요청을 분산시키는 역할 수행 -> 로드 밸런싱(load balancing)
- 캐싱 가능(WAS까지 요청하지 않아도 클라이언트 요청에 빠르게 응답)
- 민감한 WAS 정보(기기 id, MAC 주소 등)를 숨기는 보안 역할 수행
3. SSL 지원
- HTTPS의 인증서 제공
4. 웹페이지 접근 인증
- 로그인 정보(관리자, 사용자)를 WAS에서 하지 않고 Nginx에서도 가능
5. 압축
- gzip을 사용하면 클라이언트가 보낸 텍스트 파일을 압축
6. 비동기 처리
- Event loop 기반으로 상당히 많은 트래픽을 동시에 처리 가능
이외에도 다양한 기능이 많지만 특히 2번과 6번의 기능이 가장 중요하다고 할 수 있습니다. 아래 내용을 참고했으니 시간이 가능한 분들은 직접 봐도 좋을 것 같네요^^
WSGI란?
결론부터 말씀드리면 Gunicorn은 WSGI(Web Server Gateway Interface)의 일종이고(uWSGI 역시 파이썬의 대표적인 WSGI지만 Gunicorn의 퍼포먼스가 좀 더 좋고 가볍다는 의견이 대다수), Django로 서버 배포를 하기 위해서 필요로 하는 존재입니다. 그렇다면 WSGI는 무슨 개념일까요?
WSGI는 CGI(Common Gateway Interface)의 일종으로 CGI는 정적인 웹에서 동적인 웹으로 발전함에 따라 각기 다른 프로그래밍 언어가 사용되어 "공통적인 형태"로 주고받기 위해 만든 1규약(specification)입니다. 다시 말해 여러 언어 사용자들의 다양한 요청을 이해할 수 있도록 이를 공통된 규칙으로 변환하는 관문 역할을 하는 것입니다. 따라서 웹서버가 클라이언트 요청을 받으면 CGI에 의해 일관된 형태로 해석되어 이를 WAS에서 처리할 수 있는 것이죠.
CGI 기본 동작 과정
1. input으로 HttpRequest를 받음
2. 요청에 대한 정보를 환경변수 형식으로 만들어 파이썬 스크립트의 stdin 형식의 input으로 받음
3. 스크립트가 print와 같은 stdout 형식으로 응답하면 HTTP 형식으로 변환
WSGI는 파이썬 스크립트가 웹서버와 효율적으로 통신하기 위해 만들어진 인터페이스입니다. 따라서 Gunicorn이나 uWSGI 등은 Nginx로 들어오는 HttpRequest를 파이썬이 이해할 수 있게 동시통역하는 존재들입니다. 정리하자면 server/gateway side(Nginx 쪽)와 application/framework side(Django 쪽)를 둘 다 구현하고 있는 하나의 프로그램입니다. 서버에 대해선 어플리케이션 역할을 수행하고, 어플리케이션에 대해선 서버의 역할을 수행하는 셈이죠.
(추가)
CGI의 문제점: 요청이 들어올 때마다 파이썬 스크립트를 처음부터 실행하게 되어 서버가 느려지고 비효율적
이를 해결하기 위해 등장한 것이 WSGI로 스크립트 전체를 실행하는 것이 아니라 필요한 로직 하나만 실행한 후 결과 응답
WSGI 동작 과정
클라이언트 요청 -> server side에서 middleware component 호출 -> middleware component가 application side의 application 호출
Django에선 개발 목적으로 python manage.py runserver 명령어를 통해 웹 사이트를 띄울 수 있습니다. 하지만 보안이나 성능적으로 검증되지 않았기 때문에 배포 환경에선 Gunicorn을 사용하는 것입니다. 특히 WSGI는 멀티 쓰레드(multi-thread)를 생성할 수 있어 클라이언트 요청이 많아도 효율적으로 처리할 수 있다고 합니다.
참고로 Django에는 이미 WSGI 파일이 내포되어 있습니다. wsgi.py 는 프로젝트 디렉토리에 위치해 있고, django.core.wsgi.py, django.core.handlers.wsgi.py 역시 내부적으로 구현이 되어 있는 상태입니다.
그리고 참조글에서 의미있는 결론을 발견했습니다. Nginx와 Gunicorn 둘 중 하나만 써도 될까? 라는 질문에 대한 것으로 답은 모두 'Yes' 입니다.
- Gunicorn이 WSGI middleware로서 웹서버 역할을 수행하므로 Gunicorn만 써도 되지만, Nginx가 제공하는 추가적 혜택을 받지 못합니다.
- Django는 WSGI interface를 이미 어느 정도 구현했기 때문에 Nginx만 써도 되지만, seesion / cookie / routing / authentication 등의 기능을 수행하는 middleware가 없어서 하드코딩 해야 합니다.
참조
https://this-programmer.tistory.com/345
Nginx와 Gunicorn 둘 중 하나만 써도 될까? (velog.io)
- 표현하기 쉽게 WSGI가 CGI의 일종이라 했지만 사실 WSGI는 CGI에서 파생된 개념 [본문으로]
'문돌이 존버 > Django 스터디' 카테고리의 다른 글
장고(Django), Cross Site Request Forgery (0) | 2022.02.13 |
---|---|
Django, Nginx, Gunicorn, Docker 이미지 생성 및 AWS에 배포 (0) | 2021.12.06 |
장고(Django), Form & Model Form (0) | 2021.10.10 |
장고(Django), HTML Form 및 HttpRequest, HttpResponse (0) | 2021.10.10 |
장고(Django), static 파일 다루는 방법 및 extends html (0) | 2021.10.04 |