CGI와 WSGI을 파헤치다

CGI란 무엇인가?


CGI(Common Gateway Interface)는 웹서버에서 정적인 컨텐츠가 아닌 동적인 컨텐츠를 사용자에게 제공하기 위한 인터페이스입니다.

보통 웹서버의 역할은 사용자의 요청에 알맞은 페이지 혹은 데이터를 내보내는 것으로 알려져 있습니다.

하지만 그 내용이 계산이 필요하다거나, 데이터베이스에서 가져와야 해서 매번 결과가 다르다면 웹서버 혼자서는 이에 대체할 수 없습니다.

결국 웹서버가 사용자가 만든 프로그램과 통신하여 처리가 완료된 결과값을 받은 뒤 클라이언트에게 응답을 보낼 수 있는 인터페이스가 필요한 것입니다.

CGI는 이 문제를 해결하기 위해 고안되었습니다.

CGI는 인터페이스이며 특정 플랫폼에 의존하지 않고, 웹 서버로부터 외부 프로그램을 호출하는 방식을 정의해 놓은 것입니다.

CGI를 개선한 것이 바로 FastCGI입니다.

웹 서버와 프로그램이 서로 상호작용하기 위한 인터페이스임에는 변함이 없지만 CGI와는 상호작용하는 방식에 있어 차이가 있습니다.

CGI는 데이터 처리 요청이 있을 때마다 매번 프로세스를 생성하여 처리했습니다.

이 같은 성질 때문에 성능과 확장성에 한계가 존재했습니다.

요청이 늘어날 때마다 계속 프로세스가 생성되면 CPU나 Memory같은 자원이 금방 한계에 도달할 수 밖에 없기 때문입니다.

Fastcgi는 각각의 요청에 새로운 프로세스를 생성하는 것이 아니라 하나의 프로세스에서 여러 요청을 처리합니다.

CGI와는 달리 이 프로세스는 웹서버가 아닌 Fastcgi 서버가 관리합니다.

Fast CGI의 경우 다음과 같은 프로세스로 요청이 처리됩니다.

  • 클라이언트로부터 웹서버가 요청을 받습니다.
  • 웹서버가 socket이나 TCP 연결을 활용해서 Fastcgi 프로세스에게 환경변수와 페이지의 요청을 전달합니다.
  • Fastcgi가 프로그램(e.g. PHP Script)을 호출해서 응답에 필요한 데이터를 뽑아냅니다.
  • Fastcgi가 웹서버와 연결된 socket을 통해 데이터를 웹서버에게 넘겨줍니다.
  • 웹서버는 HTML 문서를 만들어서 클라이언트에게 전송합니다.


응답을 한 이후에 클라이언트와 웹서버와의 연결은 끊어지지만 이와는 상관없이 웹서버와 FastCGI 서버와의 연결은 계속됩니다.

FasgCGI 방식을 사용하면 웹서버와 FasgCGI 서버를 분리해서 사용할 수 있기 때문에 가용성이 뛰어납니다.




위와 같이 구성이 되어 있으면 한쪽 웹서버에 요청이 몰린다고 해도 2개의 FastCGI 서버를 통해 데이터 처리가 이루어지기 때문에 가용성이 뛰어나다고 할 수 있습니다.

Fast CGI는 몇 개의 프로세스가 종료되지 않고 처리를 위해 계속 상주하고 있는 형태이므로 CGI보다는 메모리 소비가 더 큽니다.

FastCGI방식이외에도 mod-perl, mod-php, mod-python처럼 웹서버에 내장 인터프리터로 동작하는 방식도 있습니다.

이렇게 하는 경우 내장된 언어를 웹서버가 해석할 수 있기 때문에 해당 언어로 서버 프로그래밍하는 것이 가능합니다.

기존 CGI 방식보다 더 빠른 것으로 알려져 있습니다.

WSGI란 무엇인가?



Nginx나 Apache같은 Web Server들은 클라이언트에게 요청이 오면 응답으로 특정 페이지를 보내줍니다.

물론, 페이지 뿐만 아니라 이미지가 될 수 있고 PDF 파일이 될 수 있고 CSS가 될 수 있습니다.

Web Server자체는 정해진 페이지(예를 들면 404 에러 페이지 혹은 Index.html 페이지)를 응답하기 때문에 클라이언트의 다양한 요청에 알맞는 응답을 보내기 위해서는 PHP같은 스크립트 언어를 사용하여 프로그래밍을 해야 합니다.

그렇다면 Python을 백엔드 언어로 사용한다면 어떻게 되는 것일까요?

Python의 Django 프레임워크는 쉽고, 빠르고, 다양한 기능들을 제공하기 때문에 근대의 뛰어난 웹 프레임워크로 평가받습니다.

Django는 웹 어플리케이션 프레임워크입니다. 그렇다면 클라이언트가 요청을 보냈을 때 어떻게 Django 어플리케이션이 요청에 알맞은 처리를 수행하고 응답을 보내게 할 수 있을까요?

Web Server가 Django에게 말을 걸 수 있는 수단이 필요합니다.

그것이 바로 WSGI(Web Server Gateway Interface)입니다.

기존의 Python 웹 어플리케이션 프레임워크는 웹서버를 선택하는데 있어 제약이 있었습니다.

왜냐하면 웹서버와 Python 프로그램이 상호작용할 수 있는 인터페이스가 제한적이었기 때문입니다.

보통 CGI, FastCGI, mod_python과 같은 커스텀 API중 하나만 사용할 수 있도록 디자인 되었습니다.
하지만 이들은 각각 문제점을 가지고 있었습니다.

  • CGI는 요청마다 프로세스를 생성하기 때문에 성능과 확장성에 한계가 존재했습니다.
  • mod_python은 웹서버 내부에 python 번역기를 달아 사용하므로 편하게 서버 프로그래밍을 할 수 있을 것이라 생각되었습니다.
    번역기가 내장되어 있기 때문에 CGI와는 달리 매 요청마다 Python interpreter를 시작할 필요가 없습니다. 이러한 장점에도 불구하고 이것을 사용하기에 몇가지 문제점이 존재했습니다.
    • PHP interpreter와는 별개로 Python Interpreter는 파일을 실행할 때 캐싱을 사용합니다. 따라서 파일의 내용이 바뀌면 웹 서버가 재시작 되어야 하는 불편함이 존재했습니다.
    • 대중적인 Apache 웹서버의 경우 child process가 요청을 핸들링합니다. 하지만 모든 child process들이 python interpreter 전체를 로드해야만 사용이 가능했습니다. 이것때문에 웹서버 성능 저하가 이슈가 발생하게 되었습니다.
    • mod_python은 특정 버전의 libpython에 의존적이었습니다. 따라서 python 구버전에서 새로운 버전으로 사용하기가 힘듭니다. 사용하려면 mod_python을 컴파일을 다시 해야하는 불편함이 존재했습니다.
  • FastCGI와 SimpleCGI는 CGI의 성능 개선을 위해서 등장했습니다.
    웹서버에서 떨어져 나와 백그라운드 프로세스를 계속 돌려놓는 방식으로 동작합니다.
    웹서버와 분리되기 때문에 안정적이고 어떤 언어로든 구현할 수 있습니다. 그리고 요청마다 프로세스를 생성하는 기존의 방식이 아니기에 성능면에서도 뛰어납니다.
    여전히 CGI와 호환되는 프로그램을 작성하는 것이 가능하지만 권장되는 방식은 아닙니다.

WSGI는 위에서 처럼 웹서버가 호출하는 프로그램으로 Python을 사용하기가 조금 힘들다는 점을 해결하려고 나온 인터페이스입니다.

Java의 경우 수 많은 웹 프레임워크들이 있지만 Java Servlet API를 활용하면 그 어떤 웹 서버에서도 돌아갈 수 있습니다.

Python도 다양한 프레임워크들이 앞서 겪었던 웹서버에 종속적이라던가 특별한 설정을 해주어야 동작하는 문제를 해결하고자 했습니다.

따라서 WSGI는 웹서버의 선택과 프레임워크 선택을 분리할 수 있도록 웹서버와 Python application간에 표준화된 통신 인터페이스를 정의한 것입니다.

우리가 WSGI 서버라고 부르는 것들은 Python App과 웹서버(e.g. Nginx, Apache)를 연결해주는 역할을 하는 것입니다.

앞에서 살펴봤듯이 웹서버가 프로그램과 상호작용하는 여러가지 방식들이 있습니다.

CGI, Fast CGI, mod_python에 대해서 살펴보았습니다.

하지만 이들의 통신 방식은 python의 여러 프레임워크마다 그리고 흔히 Proxy로 사용하는 웹서버마다 다르게 정의되었습니다.

이러한 웹서버와 python application간의 통신 방식에 존재하는 종속성을 없애기 위해 표준을 정의한 것이 바로 WSGI입니다.

그리고 표준대로 웹서버와 python application간의 다리 역할을 해줄 수 있는 구현체가 WSGI 서버입니다.

Python은 테스팅용으로 내부적으로 wsgiref라는 WSGI 서버를 가지고 있습니다.

대표적인 WSGI 서버는 flup, gunicorn, uwsgi등이 존재합니다.

댓글()