WSGI

bennn·2022년 5월 1일
0

파이썬 어플리케이션이 웹 서버와 통신하기 위한 명세가 WSGI

필요성

django는 web application server 구현을 위한 프레임워크이다.

  • WAS는 동적인 컨텐츠를 사용자의 요구에 따라 DB에서 조회하고 로직에 따라 컨텐츠를 생성한다.
  • 클라이언트는 서버에 동적인 컨텐츠만을 요구하는 것이 아니라 정적인 컨텐츠 또한 요구한다.
  • WAS가 정적인 컨텐츠까지 담당하는 것은 자원 낭비이고 이를 위한 웹서버가 따로 필요하다.

Web server가 필요하다.

  • 서버의 부하를 방지해준다. (로드 밸런싱)
    • 동적인 데이터를 처리하기 위해 상대적으로 부하가 심한 WAS의 부하를 줄인다.
    • 필요한 정적인 파일들은 WAS까지 가지 않고 Web Server단에서 빠르게 보내줄 수 있다.
  • 하나의 서버에서 여러 서비스를 호스팅할 수 있다.(Sub Domain)
  • Caching
    • 이미지, CSS, HTML, JS와 같은 정적 데이터를 Caching하여 정적파일들의 응답 속도를 빠르게 할 수 있다.
  • WAS의 보안강화
    • 사용자 정보등이 담긴 DB를 관리하는 WAS에 대한 접근을 Web Server가 하므로 보안강화를 기대할 수 있다.

WSGI는 Web server와 Python 기반 WAS가 통신하기 위한 mediator이다.

  • 기존의 웹서버들(Apache, nginx) 그 자체로는 python을 이해하지 못한다.
    • Apache의 경우 Java 기반 Web framework와 native하게 통신할 수 있다.
    • 기존의 웹서버들은 Python application을 쉽게 호출 할 수 없다.
  • Python은 bytes로 구성되는 HTTP 메시지를 이해할 수 없다.
    • WSGI는 bytes로 구성되는 HTTP 헤더와 메타데이터를 Python string으로 매핑해준다.
    • WSGI는 bytes로 구성되는 HTTP 메시지의 바디데이터를 Python Bytestring으로 매핑해준다.
  • WSGI는 Web Server가 바라보는 입장에서는 WAS로, WAS 입장에서는 Web Server로 작동한다.

WSGI통신 과정

Web Server 입장

Web Server(WSGI)는 python application에 environstart_response를 제공해야한다.

application을 호출하는 함수를 통해 전달한다.

result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result, 'close'):
            result.close()

environ

HTTP request message를 parsing한 데이터이다.

  • CGI 환경변수들
    • WSGI는 Python Dictionary 형태로 변환하여 제공한다
    • HTTP Header 관련 정보들
      • REQUEST_METHOD, SCRIPT_NAME(호스트), PATH_INFO(경로), QUERY_STRING, CONTENT_TYPE, CONTENT_LENGTH, SERVER_PROTOCOL, HTTP_Variables
  • WSGI 변수들
    • wsgi.version, wsgi.multithread, wsgi.multiprocess, wsgi.run_once
    • wsgi.url_scheme: URL의 scheme 부분 (http, https, ftp 등등)
    • wsgi.input: HTTP request body를 Bytestring 형태로 생성한 input stream
    • wsgi.errors: output stream으로 error output을 str 형태로 저장한 file-like 객체

start_response(status, response_header, exc_info=None)

  • HTTP response header를 생성하기 위한 함수로, response body를 작성하는 write(body_data) callback을 return 한다.
  • statusresponse_header를 인자로 가지고, exc_info를 optional하게 가진다.
  • status
    • python str형태의 HTTP status를 나타낸다.
    • e.g. "200 OK", "404 Not Found"
  • response_header
    • (header_name, header_value) tuple의 python list
    • response HTTP message의 헤더에 들어갈 값들을 리스트로 가진다.
    • e.g. [('Content-type', 'text/plain')]
  • exc_info
    • application에서 생긴 exception(python sys.exc_info() tuple)을 re raise한다.

Application 입장

application 호출 callable 제공

  • WAS는 Web server가 application을 호출할 수 있도록 environstart_response를 arg로 가지는 callable을 제공해야한다.

WSGI Middleware

  • 위의 WSGI명세에 따라 server/gateway side와 application/framework side를 모두 구현하고 있는 하나의 프로그램
  • 대표적으로 쓰이는 WSGI middleware에는 gunicorn과 uWSGI가 있으며 일부 python framework들은 WSGI를 내장하고 있다.

프레임워크 내장 WSGI

  • django, flask의 경우 WSGI interface를 어느정도 구현해놓았으므로 바로 Web server를 붙여 써도 된다.
  • 그러나 session, cookie, routing, authentication 등의 기능을 쉽게 적용하기 위해서는 gunicorn 혹은 uWSGI를 사용하는 것이 좋다.

gunicorn

  • WSGI 명세와 필요한 기능들을 간단히 구현한 middleware이다.
  • 간단하고 서버의 리소스를 적게 쓴다.
  • 웹서버로 nginx와 붙여 쓰는 것이 권장된다.

uWSGI

  • gunicorn에 더해 고급 기능들을 더 구현한 middleware
  • 순수 c로 작성되어있다.
  • 더 많은 기능들을 WAS상에서 구현하고 웹서버단은 간단히 하고자 할 때 유용할 것 같다.(추측)

서비스 구조의 변화

  • 실제 서비스에서는 꼭 전통적인 WebServer - WSGI - WAS 구조를 따르는 것은 아니다.
  • 다양한 배포환경에서 Apache나 NginX 웹서버를 설정하지 않는 경우가 존재한다.

서버리스 서비스

  • 서버리스 서비스는 서버 셋업없이 web application code를 실행할 수 있는 FaaS 환경이다.
  • 서버리스 서비스는 웹서버와의 연동이 아닌 클라우드 서비스 플랫폼의 다른 서비스들과 연동된다.

문제점

  • WSGI는 Web Server로부터 Http Message를 Input으로 받는 경우를 전제로 한다.
  • 하지만 Lambda는 서버리스 서비스이고 aws api gateway로부터 HTTP Message를 입력받지 않는다.
    • lambda 실행을 위한 json 형태의 변수들을 입력받는다.

해결방법

  • zappa와 같은 serverless 배포에 사용되는 프레임워크를 이용한다.
    • WSGI가 HTTP message를 input으로 받도록 WSGI wrapper 기능을 제공한다.

Python application을 통한 정적 파일 serving

  • static file을 서버에 저장하지 않고 CDN서비스를 통해 serving되는 경우 고려할 수 있다.
  • Whitenoise와 같은 library는 webserver를 거치지 않고 정적 파일을 제공할 수 있도록 한다.
    • web server를 붙이기 힘든 배포환경일 때 유용하다.
    • caching Header를 통해 CDN에서 정적파일이 효율적으로 직접 serving할 수 있게 한다.
    • application이 CDN의 URL을, CDN이 application의 URL을 알 수 있게 연결한다.
    • 여전히 WSGI를 이용해 file을 sendfile syscall을 이용해 효율적으로 보낼 수 있다.
    • static file의 serving또한 python으로 쉽게 테스트할 수 있고, git으로 관리된다.

참고

https://peps.python.org/pep-3333/

https://velog.io/@denhur62/nginx-와-uwsgi를-왜-사용할까

https://medium.com/analytics-vidhya/what-is-wsgi-web-server-gateway-interface-ed2d290449e

https://nitro04.blogspot.com/2020/01/django-python-asgi-wsgi-analysis-of.html

https://wayhome25.github.io/django/2018/03/03/django-deploy-02-nginx-wsgi/

https://tech.junhabaek.net/zappa와-github-action을-활용한-서버리스-django-application-aws-배포-트러블-슈팅-15604ed6bbcc

https://velog.io/@jimin_lee/Nginx와-Gunicorn-둘-중-하나만-써도-될까

http://whitenoise.evans.io/en/stable/

profile
🐾

0개의 댓글