WSGI 란?

WSGI 란?

Python 으로 서버 개발을 하다보면 WSGI, uWSGI, Werzeug 등의 단어들이 자주 보인다.

본 포스트에서는 이것들에 대해 알아본다.

Web Server 와 Web Application

우선 Web Server 의 개념과 간단한 히스토리를 알아야 한다.

Web Server 는 다소 광범위한 용어라서 Hardware 로서의 의미와 Software 로서의 의미를 함께 가지고 있다. 하지만 여기서는 Software 로서의 의미에 대해 이야기하겠다.

Web Server 는 Client 의 정적인 리소스(File, Image, HTML page, ...) 요청을 처리하는 프로그램이며, 대표적으로 Apache HTTP Server 와 Nginx 가 있다.

그리고 동적인 요청이 들어오면 비즈니스 로직을 수행하기 위해 Web Application(혹은, WAS, AS) 에게 요청을 위임하고, Web Application 은 Web Server 에게 로직을 수행한 결과를 다시 돌려준다.

그럼 Web Server 가 Web Application 과 대화할 수 있는 인터페이스가 필요할 것이다.

특히, 다양한 종류의 Web Server 와 Web Application 을 Interchangable 하게 사용하기 위해서는 잘 정의된 인터페이스가 필수다.

CGI

2003년까지 Python Web Framework 는 주로 CGI 와 같은 방식으로 Web Server 와 대화했다.

CGI(Common Gateway Interface) 는 다음과 같이 동작한다.

  • 먼저 Web Server 가 Client 로 부터 HTTP Request 를 받는다.
  • Web Server 는 Request 에 대한 정보(Method, Url, Parameters, ...)를 Environment Variable 과 Standard Input 을 통해 전달하면서 Script 를 실행한다.
  • Script 는 비즈니스 로직을 수행하고 Standard Output 으로 결과를 Web Server 에게 전달한다.
  • Web Server 는 이를 다시 Client 에게 전달한다.

문제는 매번 다시 스크립트를 실행하여 메모리에 적재하는 과정에서 발생하는 추가적인 시간 소요 등이었다.

이 때 2003년에 Python 표준(PEP333)인 WSGI 가 등장하게 된다.

WSGI

WSGI(Web Server Gateway Interface)(위스키라고 읽는다) 는 Callable Object 라는 녀석을 통해 Web Server 가 요청에 대한 정보를 Application 에 전달한다.

Callable Object 는 Function 이나 Object 의 형태가 될 수 있으며, Web Server 는 Callable Object 를 통해 2가지 정보를 전해주어야 한다.

  • HTTP Request 에 대한 정보(Method, URL, Data, ...)
  • Callback 함수

다음은 각각 함수와 클래스 형태로 정의된 Callable Object 의 예이다.

environ 이 HTTP Request 에 대한 정보를 담고 있고, start_response 가 Web Server 에게 결과를 돌려주기 위한 콜백 함수다.

def application(environ, start_response):
body = b'Hello world!\n'
status = '200 OK'
headers = [('Content-type', 'text/plain')]
start_response(status, headers)
return [body]
class Application:
def __init__(self, environ, start_response):
self.environ = environ
self.start_response = start_response

def __iter__(self):
body = b'Hello world!\n'
status = '200 OK'
headers = [('Content-type', 'text/plain')]
self.start_response(status, headers)
yield body

Web Application 는 HTTP Request 에 대한 정보를 가지고 Business Logic 을 수행한 뒤에 Callback Function 을 통해 결과를 웹서버에 반환한다.

이러한 WSGI Interface 를 구현하는 Web Server 나 Application 을 WSGI compatible 하다고 하며,

WSGI compatible 한 Application 을 WSGI Application 이라고 부르기도 한다.

또한, 이 WSGI 인터페이스를 구현하기만 한다면 누구나 Python Web Server 나 Python Framework 를 만들어서 기존에 WSGI 를 지원하던 웹서버나 프레임워크와 함께 동작하게 할 수 있다.

WSGI Middleware

Web Service 를 개발하다 보면 공통적으로 필요한 기능들이 있는데, Authentication, Routing, Session, Cookie, Error Page 보여주기, ... 와 같은 기능들이다.

WSGI Middleware 는 Middleware 라는 이름처럼 Web Application 의 실행 전과 후에 이러한 기능들을 추가해주는 녀석이며, 그 자체로도 WSGI Application 이다.

Design Pattern 의 Decorator Pattern 을 생각하면 이해가 쉽다. 양파 껍질 처럼 Web Application 을 감싸고 있는 구조이다.

uWSGI, Gunicorn, Werkzeug

글 맨 처음에 언급한 uWSGI, Gunicorn, Werkzeug 과 같은 라이브러리들이 바로 위에서 이야기한 WSGI Middleware 의 기능을 가진 라이브러리들이다.

WSGI Middleware 역할 외에도 uWSGI, Gunicorn, Werkzeug 은 자체적으로 Web Server 의 역할을 할 수도 있다. 그래서 WSGI Server 나 Stand alone WSGI Container 라고 불리기도 한다.

Flask 에서 기본적으로 사용하는 WSGI Middleware 가 Werkzeug 인데, 별다른 설정없이 Flask 앱을 실행 해보면

Production 에서는 사용하지 말라는 경고 문구가 나올 정도로 단순한 개발용 서버를 내장하고 있다.

Production Level 에서는 Nginx, Gunicorn, Django 와 같은 식의 구성을 많이 사용하기도 한다.

Nginx 는 주로 Buffering, Reverse Proxying, Load Balancing 등의 기능을 위해 Gunicorn 앞단에 배치하고,

Gunicorn 은 Django 로 작성한 Web Application 에 HTTP 요청을 전달해주는 역할의 WSGI HTTP Server 로서 사용하는 것이다.

Gunicorn 을 사용할 땐 worker process 의 개수와 worker class(async 방식인 Gevent, Tornado, ...)를 설정하여 요청 처리 성능을 높일 수 있다.

더 읽을거리

https://www.ibm.com/cloud/learn/web-server-vs-application-server
https://www.nginx.com/resources/glossary/application-server-vs-web-server/
https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface
https://en.wikipedia.org/wiki/Common_Gateway_Interface
https://www.python.org/dev/peps/pep-0333/
https://www.youtube.com/watch?v=WqrCnVAkLIo
http://xplordat.com/2020/02/16/a-flask-full-of-whiskey-wsgi/

Comments