얼마 전에 다른 회사 개발자 친구들과 Flask 를 FastAPI 로 변경하는 이유에 대한 토론을 하게 되었다. 이 이야기를 하면서 왜 굳이 바꾸어야 하는가에 대한 여러 이야기를 하게 되었다.
그 이유는
- Flask 가 오래되어서 새로운 Framework 를 써보고 싶다.
- Flask 가 WSGI 기반이라서 성능 개선을 위해 ASGI 기반인 FastAPI 로 바꾸고 싶다
개발자들이라면 새로운 Framework 를 써보고 싶다는 것에 크게 공감이 될것 같다. 하지만, 실제로 운영하는 서비스를 변경하는 것이었기에 왜 그럴까에 대한 이야기를 나누다보니 ASGI 기반인 FastAPI 를 적용하여 성능 개선을 하고 싶다는 이야기까지 하게 되었다.
하지만, 파이썬의 경우 ASGI 기반의 FastAPI 를 적용하여도 Database Driver 도 비동기 방식으로 바꾸지 않는다면, 성능 개선의 효과가 크지 않다. 즉, Rest API 의 요청은 Async 지만, 그 뒤는 Database 연결이 Sync 로 동작하게 되므로 결국 Aync 가 아니라 Sync 로 처리 된게 된다.
이런 이야기를 나누다가 나도 ASGI, WSGI 에 대한 것들을 두리뭉실하게 알고 있는것 같아서 이를 정리 해보려고 이 글을 적는다 :)
Web Server
- HTTP Request 에 맞는 웹페이지를 Response 해주는 기능을 가짐(Static, 정적임)
- 정적 이란?
Web Server 에 있는 웹페이지를 그대로 Response 함
웹페이지가 변경 되지 않는 동일한 웹페이지를 Response 함
Web Application Server
- Web Server + Web Container( = Web Server + CGI)
= WAS(Web Application Server) - Web Server 가 동적으로 동작하면 Web Application Server
- 동적이란?
Request 에 따라 데이터를 가공하여 생성된 웹페이지를 Response
Request 에 따라 Response 되는 웹페이지가 달라짐
** Web Server, Web Application Server 를 구분하는 이유
- 다양한 로직 처리를 Web Application Server 로
단순한 정적 처리를 Web Server 로 나누어 서버 부하 감소
= 정적 컨텐츠까지 WAS가 처리한다면 부하가 커져 수행 속도가 느려질 수 있음 - SSL 처리를 Web Server 로 분리하여 보안 강화
- 자원 이용의 효율화, 유지 보수 편의성을 위해 구분
CGI(Common Gateway Interface)
- 가장 오래된 Interface(= 거의 모든 Web Server 지원)
- Web Server 와 이를 호출하는 Application 간의 인터페이스
= Web Server 에서 Application 을 실행 하는데 필요한 Interface 로 단순히 Request 를 Response 해주는 Web Server 의 역활(Static)을 동적으로(Dynamic)하게 개선해주기 위한 목적을 가짐 - Web Server 의 process 에 interpreter 에 상주 하여 성능을 개선하는 Java Servlet, FastCGI .. 등도 있음
= Web Server 에 HTTP Request 가 오면 interpretor 에서 감지하여 프로세스를 fork 하여 내부에서 처리함
** CGI(Common Gateway Interface), WAS(Web Application Server) 차이
- 동일한 요청이 많은 경우 CGI 는 모든 Request 에 대해 모두 실행하지만, Web Application Server 는 한번만 실행하므로 WAS 가 더 효과적임
WSGI(Web Server Gateway Interface)
- Web Server 의 Request 를 Python Application 으로 보내주고 Response 를 받아서 Web Server 로 보내주는 Web Server Gateway Interface 임
- Web Server 의 Request 를 Callable Object 를 통해 Application 에 전달Callable Object 는 Function 이나 Object 의 형태로 HTTP Request 에 대한 정보(Method, URL, Data, …), Callback 함수 정보를 전달
- 2003년 파이썬 표준으로 WSGI 가 나온 이후 현재까지 사용됨
- WSGI Middleware 는 WSGI 의 구현체로 Request 를 Flask, django 와 같은 Web Framework 에 연결하는 WSGI server의 역할을 함(gunincorn, uWSGI, Werkzeug 등이 있음)
- WSGI 는 Synchronous 하게 작동하기에 동시에 많은 Request 를 처리하는데 한계가 있음(Celery, Queue 를 이용하여 성능 향상 가능)
** Flask, django 에서 WSGI compatible server 기능이 있는데 WSGI Middleware 를 써야 하는가?
- Flask, django 만 사용해도 되지만, Flask/django 가 제공하는 WSGI compatible server 는 개발을 목적으로 구현된 것으로 운영 환경에서의 트래픽을 감당하는데 적합하지 않을 수 있음
** WSGI Middleware 없이 Nginx 같은 Web Server 를 써야 하는가?
- Flask/django 같은 Web Framework 의 경우 WSGI interface 가 일부 구현된 compatible server 기능을 제공 하고 있기 때문에 Nginx 만 사용해도 된다.
- Gunicron/uWSGI 을 이용하는 경우 멀티쓰레드를 지원하여 더 많은 Request 를 처리 할 수 있음
ASGI(Asynchronous Server Gateway Interface)
- WSGI 와 비슷한 구조를 가지나 기본적으로 모든 요청을 Asynchronous 로 처리하는게 다름
- WSGI 에서 지원 되지 않는 Websocket, HTTP 2.0 을 지원함
- ASGI 는 WSGI 와 호환됨(=ASGI는 WSGI의 상위 버전임)
- WSGI 가 Synchronous 하게 작동함으로써 발생하는 한계를 해결하기 위해Uvicorn 과 같은 Asynchronous Server Gateway Interface 가 나옴
=> WSGI의 단점은 요청을 받고 응답을 반환하는 단일 동기 호출 방식이라는 것
=> 웹소켓을 사용할 수 없음. wsgi.websocket을 사용할 수 있지만, 표준화안됨 - 단일 astnchronous(비동기) 호출이 가능 하므로 여러 이벤트를 주고받을수 있음
=> 대용량 트래픽 처리를 유연하게 할 수 있음