Spring 에 비유하면, 만들어진 웹 서비스를 Tomcat 등의 "WAS"로 배포를 한다. Python에서는 이러한 WAS를 제공해주지 않고 run time환경에서 돌아간다. 그렇다면 어떤 방법으로 웹 서버와 Python 애플리케이션을 연결할 수 있을까?
Django applications are WSGI applications. WSGI means Web Server Gateway Interface (modern and better version of old CGI, that's why sometimes called FastCGI). So you need an Application Server in the first place which can serve WSGI applications. Gunicorn and uWSGI are common and mostly used application servers for hosting Django projects in production.
Now where's and who's the web server?
In production, its a common practice to have a common web server like Nginx or Apache to run on port 80 (the common HTTP port where browser hits when you don't mention any port in URI) and support secure connections in 443 (HTTPS). This web server (a particular server block or more commonly a VirtualHost) is configured to act as a reverse proxy for all requests meant for your application server. In simpler terms, your web server simply passes on the requests meant for your django application to the same and let the client get back the response the application server sent back. There's another important function of the web server and that is to serve static web asset files (Images, Fonts, CSS, JS). Same way whenever it gets a request at a particular url (like for example /static) it knows Nginx/Apache itself has to respond back with the resource requested.
To keep the application server running in background we need to register those as Services in the operating system (I have experience with Linux and not much with Windows).
You can read more about reverse proxies and working of this web servers and WSGI. The question suggests that you are pretty new to these and I appreciate your inquisition if you are ready to study and perhaps host a few django apps in Linux servers yourself. I purposely left the discussion incomplete about how the Application Server is identified by the web server to encourage research on your end.
PS: Although this question is Django specific, the approch of having an Application Server running in some other port and Web servers used as reverse proxy is generic. Infact NodeJS or any other web applications are served in similar ways. Also I am pretty aware there are other approaches to it and that it is often modified depending on the load balancing and other optimisations for scaling. Sometimes Docker or similar containerization tools are used but the idea is same even then.
(from : https://www.quora.com/Does-Django-need-a-web-server )
웹 서버 상에서 사용자 프로그램을 동작시키기 위한 조합이다. 존재하는 많은 웹 서버 프로그램은 CGI의 기능을 이용할 수 있다.
웹 서버 프로그램의 기능의 주체는 미리 준비된 정보를 이용자(클라이언트)의 요구에 응답해 보내는 것이다. 그 때문에 서버 프로그램 그룹에서는 정보를 그 장소에서 동적으로 생성하고 클라이언트에 송신하려하는 조합을 작성하는 것이 불가능했다. 서버 프로그램에서 다른 프로그램을 불러내고, 그 처리 결과를 클라이언트에 송신하는 방법이 고안되었다. 이를 실현하기 위한 서버 프로그램과 외부 프로그램과의 연계법을 정한 것이 CGI이다.
CGI는 환경변수나 표준입출력을 다룰 수 있는 프로그램 언어에서라면 언어의 구별을 묻지 않고 확장하여 이용하는 것이 가능하나, 실행속도나 텍스트 처리의 용이함 등의 균형에 의해 펄이 사용되는 경우가 많았다. 최근에는 펄뿐 아니라 파이썬, 루비 등도 널리 쓰이고 있다.
기본적으로 웹 서버 자체는 정적인 페이지 밖에 보여주지 못한다. "웹서버와 웹어플리케이션서버에 대한 이해 필요"
우리가 인터넷에서 보는 동적인 페이지들은 웹 서버가 전적으로 처리하는 것이 아니라 웹 어플리케이션(장고, 플라스크 등으로 작성된 프로그램)의 도움으로 보게 된다. 그래서 웹 서버와 웹 어플리케이션은 서로 소통을 할 수 있어야 한다. 하지만 아파치, Nginx 등의 웹 서버는 런타임 환경의 파이썬 코드를 이해하지 못한다. 그래서 "생(코드 날것)"으로 웹 서버와 파이썬 웹 어플리케이션은 소통을 할 수가 없다.
FastCGI는 몇 번의 요청이 들어와도 하나의 프로세스만을 가지고 처리하게 된다. 즉 메모리에 단 하나의 프로그램만을 적재하여 계속 재활용하기 때문에 CGI에 비하여 오버헤드가 월등하게 감소한다.
Java의 Tomcat 또한 Web Server + FastCGI를 채택한 형태로 다수의 사용자 접속에 유리하다. 우리는 JVM 계열의 언어로 서버 프로그램을 작성하면 JBoss, Tomcat 등의 웹 애플리케이션 서버를 사용하는 게 보편적이지만 이 외에도 우리가 CGI를 수동으로 붙여서 사용할 수 있는 방법도 있다. => 물론 해당 CGI를 만들어야 하긴 한다.
그러나 Python에서는 이러한 WAS가 별도로 존재하지 않으며 결국 우리가 CGI, FastCGI 등을 이용해서 원하는 WAS 형태를 만들어 사용해야 한다. 그래서 등장한 것이 Python만의 게이트웨이 인터페이스다!
Django(MVT 디자인패턴)를 기준으로 보는 모습이다. WSGI는 CGI와 동일하게 웹 서버와 애플리케이션 중간에 위치하는데, CGI와 다른 점은 CGI는 매 요청마다 프로세스를 생성한다는 점이고, WSGI는 한 프로세스에서 모든 요청을 받는다.
위에서 말한 것 과 같이 CGI는 매 요청마다 Fork 등의 함수를 통해 커널 리소스를 추가/반납하고, WSGI는 많은 요청을 콜백(callback)으로 받아 처리하게 된다.
WSGI는 웹 어플리케이션을 호출할 때 요청(request)의 헤더 부분을 "환경 정보로 전달"하며 이 때 "콜백 함수"도 같이 전달합니다. 그 후 웹 어플리케이션이 요청을 처리하고 콜백 함수로 응답하는 방식입니다.
이런 WSGI를 도입하기 위한 대표적인 두 가지 방법
결국 WSGI는 웹 서버와 애플리케이션 사이에 미들웨어 역할을 하며 기술적으로는 웹 서버도 WSGI에 대한 작동 코드가 필요하고, 애플리케이션 또한 WSGI에 대한 작동 코드가 필요한 Client-Server Model을 응용한 것.
즉, 웹 서버가 애플리케이션의 코드를 직접적으로 읽을 수 없으므로 중간의 미들웨어가 해당 코드를 읽어서 결과를 대신 반환해주는 이라고 쉽게 이해할 수 도 있다.
이제 wsgi가 무엇인지 이해를 했으니 해당파일의 존재 이유를 파악할 수 있다. 사실 장고의 내장 서버는 WSGI의 기능을 자체적으로 포함하고 있다는 것이다 -> python manage.py runserver
WSGI 서버는 장고와 통신할 때 '프로젝트명/config/wsgi.py' 경로에 있는 이 파일을 통해 장고 어플리케이션을 호출한다.
이 파일은 웬만해선 딱히 건들 필요가 없지만 혹시나 프로젝트의 디렉터리 구조를 조금 손봐서 settings.py 파일이 이동하게 된다면 그 경로를 반드시 수정 해야 한다.
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
# application의 settings.py의 경로를 찾아간다!
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()
Python에서는 asyncio, coroutine과 같은 비동기 처리를 지원한다. 그러나 WSGI는 동기 함수 처리만을 지원하여 여러 작업을 동시에 처리하는 것에 한계가 있습니다. 가령 현대 웹 서비스에서는 웹 소켓 등을 사용한 실시간 채팅 서비스 등을 할 수도 있는데, WSGI로는 이러한 서비스를 구현하는 데 어려움이 생길 수 밖에 없는 것.
Celery 등을 활용하여 대용량 트래픽 처리 요구하는 서비스가 불가능한 것은 아니라고 한다. 하지만 추적, 유지 보수, 기본적인 구현 측면에서 쉬운 길이 아니라는 것.
따라서 최근에는 Django 3.0 뿐만 아니라 FastAPI 등의 프레임워크에서도 ASGI 인터페이스를 적용하였으며 뒤따라 Falcon 프레임워크도 3.0부터 ASGI 개발에 들어갔다.
운영 아키텍처로 봤을 때는 크게 다르지 않지만 WSGI와 다르게 ASGI는 기본적으로 요청을 비동기로 처리한다는 점이 크게 다르다. 따라서 WSGI에서는 지원되지 않는 Websocket 프로토콜과 HTTP 2.0을 지원한다.
"단일 비동기 방식으로 구성"되어 있고, send, receive 함수를 제공하는데 이 함수들을 비동기적으로 호출하여 이벤트를 처리합니다. 여러 송수신 이벤트를 허용 할 수 있을 뿐만 아니라 백그라운드 코루틴도 허용하므로 redis 큐와 같은 외부 트리거 이벤트를 읽는 것과 같은 어플리케이션의 다른 작업도 수행할 수 있다.
ASGI는 WSGI의 상위 집합 개념으로 설계되었으며 asgiref 라이브러리를 사용해 ASGI 서버 내에서 WSGI를 실행할 수 있다.
이러한 대표적인 ASGI Web-App에는 python에서 uvicorn이 있다. uvicorn은 ASGI 기반의 웹 애플리케이션 서버로써 그 내장 모듈로 uvloop을 사용한다. uvloop에서 uv는 libuv 즉, Javascript V8에서 사용되는 비동기 모듈을 사용한 것이다.
ASGI는 Cython 기반으로 C++ 언어로 작성되어 매우 빠른 속도를 제공한다는 것이 특징인데다가 libuv를 사용하여 비동기 처리를 하니 Node.js와 같은 비동기 처리 속도를 어느 정도 누릴 수 있다는 장점이 있다.
django 배포의 A to Z 가 아니라 우선 기본적인 "방향과 방법"에만 집중해서 "어떻게 배포를 할지" 에 대한 얘기만 하려고 한다.
여기서 Django를 사용한다면, 런타임 언어에 "왜 배포를하지?" 라는 의문이 생길 수 도 있다. 우선 기존 Django의 배포에 대해 다 보고, 이해를 다시 처음부터 하는 것을 추천한다. 그리고 방대한 공식문서를 꼭 이용하자
Django는 현재 WSGI와 ASGI의 두 가지 인터페이스를 지원한다.
응용 프로그램에 대해 static files를 어떻게 처리할 것인지와 error reporting을 어떻게 처리할 것인지도 고려해야 한다.
마지막으로 애플리케이션을 운영 환경에 배포하기 전에 '배포 체크리스트'를 확인하여 구성이 적합한지 확인해야 한다. 공식 문서를 참고하면 좋다.
일단
python manage.py check --deploy
부터 해보세요!
인터넷은 적대적인 환경입니다. 여러분의 장고 프로젝트를 배포하기 전에, 보안과 성능, 연산에 관련해서 설정을 다시 살펴볼 시간이 필요합니다.
장고는 보안 기능을 많이 갖고 있습니다. 몇몇은 내장된 기능으로 항상 켜져있습니다. 다른 몇몇은 선택할 수 있는데 그 이유는 항상 보안 기능들이 적절하지 않거나 개발에 불편함을 가져올 수 있기 때문입니다. 예를 들어 강제로 HTTPS를 활성화 하는 것은 모든 웹사이트에 적합하지 않을 수도 있고, 로컬 개발환경에선 비실용적일 수도 있습니다.
성능 최적화는 편의를 위한 또다른 범주의 거래입니다. 예를 들어, 캐싱은 상용 환경에서 유용할 수 있지만 로컬 개발 환경에서는 실용적이지 않을 수 있습니다. 오류 보고의 필요성에도 큰 차이가 있습니다.
설정에 대한 체크리스트는 다음과 같습니다.
이 설정들 중 대부분은 예민할 수 있고 감추어져야 합니다. 만약 여러분이 프로젝트의 소스코드를 배포한다면, 대부분은 개발 환경에 최적화된 설정으로 배포하고 상용 환경에서 사용할 별도의 설정을 사용할 것입니다.
이후 특별 환결 설정과 HTTPS, 성능 최적화, 오류 알림에 대해서는 꼭 읽어보는 것을 추천한다.
Gunicorn(Green Unicon)
는 UNIX용 Pure-Python WSGI 서버다. 종속성이 없으며 《파이프》를 사용하여 설치할 수 있다.
python install gunicorn
을 실행하여 gunicorn
을 설치한다.
일반적인 WSGI 애플리케이션으로 Gunicorn에서 Django 실행
gunicorn myproject.wsgi
127.0.0.1:8000
에서 "하나의 스레드"를 8000번 포트를 리스닝하는 하나의 과정을 시작할 것이다. 프로젝트가 Python 경로에 있어야 한다. 동일한 디렉토리에서 실행하는 가장 간단한 방법이다.gunicorn [project명].wsgi -b 0.0.0.0 —workers 1
과 같은 방식으로 WAS 인스턴스를 러닝한다. Nginx, Gunicorn 배포 글을 추천한다.
화해에서도 WSGI를 기반으로 gunicorn 활용해서 BE API를 배포한다. 화해의 gunicorn A to Z 글을 꼭 추천한다. 디테일한 부분이 gunicorn의 공식 가이드보다 읽을 만 하다!
python -m pip install uvicorn gunicorn
설치하기.
Uvicorn이 설치되면 ASGI 응용 프로그램을 실행 하는 uvicorn 명령을 사용할 수 있다. Uvicorn은 ASGI 응용 프로그램 개체를 포함하는 모듈의 위치와 그 뒤에 응용 프로그램이 호출되는 위치 (콜론으로 구분)를 사용하여 호출해야 한다.
일반적인 Django 프로젝트의 경우 Uvicorn을 호출하면 다음과 같다.
gunicorn myproject.asgi:application -k uvicorn.workers.UvicornWorker
그리고 보통 gunicorn 러닝을 데모나이징해서 service
를 만들어서 구동을 하는 형태가 많다.
Django는 동적인 웹 애플리케이션을 위해 설계되었지만 정적 파일(이미지, CSS, JavaScript 파일 등)을 처리하는 데에는 더 효율적인 웹 서버가 적합하다.
Nginx는 정적 파일을 처리하는 데 특화되어 있으며, 이를 위해 Django 애플리케이션에 대한 요청 중에서 정적 파일 요청을 처리하는 역할을 할 수 있다. 이렇게 함으로써 애플리케이션 서버의 부담을 줄이고, 정적 파일 제공에 더 빠른 응답을 할 수 있다.
[Python] REST API 개발로 알아보는 WSGI, ASGI <- 이미지는 모두 해당 블로그에서 가져왔습니다. 정리를 정말 잘해두셨습니다.