Python/Python

[Python] 파이썬에서 웹서버는 어떤 구조로 통신할까?

YounghunJo 2024. 7. 21. 17:42
반응형

이번 포스팅에서는 파이썬을 활용하는 웹서버에서 클라이언트와 어떤 구조로 통신하는지에 대해 알아보려고 한다. 참고로 앞으로 소개할 내용은 애플리케이션 레벨 정도(컴퓨터 구조로 친다면 OS의 Kernel 모드 정도의 수준까지) 까지의 구조를 이야기하며 웹서버의 종류에 대해서 소개할 때는 Pyhton에만 국한된 이야기를 하려고 한다.

 

필자도 여태껏 개발해오면 Python을 활용해서 웹서버를 개발할 수 있는 여럿 프레임워크를 만지고 다루기도 해보았다. 대표적으로 Flask가 있고, 요즘에는 FastAPI가 있다. 기타 풀스택 프레임워크도 사용해보았지만, 여기서는 주로 백엔드 서버를 구성하는 데 사용되는 Flask, FastAPI가 주요 타겟일 것 같다.

 

비록 예전 포스팅에서 웹서버가 역사적으로 어떤 방식으로 발전되어 왔는지 소개하면서 배우긴 했지만, 막상 현업에서 주로 FastAPI를 사용해오다가 Python에서는 그럼 구체적으로 어떤 구조로 동작하는지 궁금증이 생겼다. 이를 천천히 하나씩 살펴보도록 하자.

 


1. 웹에서 통신하는 전형적인 구조

웹에서 클라이언트와 서버 간에 통신하는 전형적인 구조가 있다. 여기서 클라이언트라고 하면 정말 웹브라우저로 접속하는 유저(사람)가 될 수 있고, 또 다른 서버가 될 수 있다. 일단 먼저 아래 그림을 살펴보자.

 

파이썬에서 웹 통신 구조

 

클라이언트는 웹 브라우저를 사용하는 유저가 될 수도 있고, 또 다른 서버가 될 수 있다.

1-1. 웹 컨텐츠를 전달해주는 소프트웨어: 웹 서버

만약 클라이언트가 유저라면 클라이언트의 요청이 가장 먼저 닿는 부분은 웹 서버라고 하는 부분이다. 만약 클라이언트가 또 다른 서버라고 한다면 경우에 따라 웹 서버라는 부분을 생략할 수도 있다.

 

어쨌건 여기서 웹 서버는 대표적으로 Apache HTTP Server 나 프록시 서버로 주로 이용하는 Nginx 서버 등을 사용한다. 이 웹 서버는 주로 클라이언트가 요청한 웹 컨텐츠(이미지나 HTML 문서 등)의 전달을 도와준다. 특성은 바로 '정적'이라는 것이다. 즉, 요청을 보낸 클라이언트가 어떤 클라이언트인지에 상관없이 모두 동일한 리소스만 전달해준다는 것이다. 이 서버를 흔히 이야기하는 '프론트엔드' 서버라고 한다.

1-2. 웹 서버와 웹 애플리케이션 서버 간의 통신을 도와주는 조력자: Gateway Interface 서버

웹 서버를 거치고 난 요청은 보통 클라이어트에 따라 동적인 값을 생성하기 위해 웹 애플리케이션 서버로 향한다. 하지만 웹 서버는 프로그래밍 언어(여기서는 Python)로 작성된 스크립트를 직접적으로 해석하지 못한다. 예를 들어, Apache HTTP Server는 Flask 프레임워크를 이용해서 작성된 파이썬 스크립트를 직접 해석하지 못한다는 것이다. 

 

비영어권인 한국인, 일본인, 중국인은 서로 모국어만을 사용하면서 소통을 하면 당연히 알아듣지 못한다. 하지만 만국 공용어인 영어를 사용하게 된다면 영어 공부를 한 한국인, 일본인, 중국인은 '영어' 라는 공통의 수단을 통해서 소통이 가능해진다. 

 

웹 통신에서도 마찬가지다. 바로 Gateway Interface 서버가 '영어' 같은 역할을 하는 셈이다. Python에서의 대표적인 Gateway Interface 서버로는 WSGI(Web Server Gateway Interface)와 ASGI(Asynchronous Server Gateway Interface)가 있다. 이 WSGI, ASGI는 추상화된 개념이고 이를 실질적인 구현체로 구현한 것들이 따로 있다. WSGI 구현체로는 gunicorn, mod_wsgi, uWSGI 등이 있다. WSGI, ASGI 간의 차이점에 대해서는 좀 더 하단에서 알아보도록 하자.

 

또한 Gatway Interface 서버는 클라이언트의 HTTP 요청을 TCP/IP 계층 수준에서 접근하고 제어할 수 있다. 이는 웹 애플리케이션 서버에서 하지 못한다는 점도 알아두자.

1-3. 동적인 값을 생성하는 서버: 웹 애플리케이션 서버

방금 전 소개한 Gateway Interface 서버는 웹 서버로부터 보내온 내용을 웹 애플리케이션 서버가 알아들을 수 있는 내용으로 일종의 번역을 수행해서 웹 애플리케션 서버로 전달해준다. 좀 더 구체적으로는 Gateway Interface 서버에서 환경 정보와 콜백함수 등을 전달해주면 웹 애플리케이션 서버에서는 DB나 써드파티 API 등과 연결되어 클라이언트에 따른 동적인 응답값을 처리하고 난 뒤 전달받은 콜백함수를 호출하면서 해당 응답값을 다시 Gateway Interface 서버로 전달해준다.

 

이렇게 번역된 내용을 전달받은 웹 애플리케이션은 DB나 써드파티 API 등과 연결되어 클라이언트에 따른 동적인 값을 처리할 수 있게 되는 것이다.

 

이 웹 애플리케이션 서버가 바로 우리가 흔히 접하는 Flask, FastAPI, django 등과 같은 웹 (애플리케이션) 프레임워크인 것이다. 보통의 개발자들이 소스코드를 작성하는 곳이기도 하다.

 

보통 Gateway Interface 서버는 이른바 '미들웨어' 라고도 부르며 보통 웹 애플리케이션 서버와 같이 붙어있게 된다. 그리고 이 두개를 합쳐서 보통 '백엔드' 서버라고 부른다.

2. WSGI vs ASGI 간의 차이점은 뭘까?

1번 목차에서 개괄적인 구조를 알아보았다. 이번 목차에서 알아볼 것은 미들웨어라고 불리는 요소에서 사용되는 대표적인 것 중 WSGI, ASGI 간의 차이점에 대해서 알아보도록 하자. 역사적으로 보면 WSGI 라는 것이 먼저 등장하였다.

2-1. 동기(synchronous) 처리 but 멀티 프로세스 가능: WSGI

제목 그대로 나와 있듯이, WSGI의 대표적인 특징 중 하나로는 클라이언트의 요청을 동기로 처리한다는 점이다. 반대로 말하면 비동기 처리가 불가능하여 동시성(concurrency 이라고 하며 동시성에 대한 구체적인 의미는 저번 포스팅에서 알아보았으므로 참고) 처리가 불가능하다는 이야기다.

 

비동기 처리가 불가능하지만 대신 WSGI 에서는 프로세스를 여러 개 띄워 다수의 요청을 병렬적으로 처리하는 것이 가능하다. 대표적인 WSGI 구현체의 예시로는 gunicorn, mod_wsgi, uWSGI 등이 있다. 

 

물론 WSGI 에서는 그러면 아예 비동기 처리가 불가능하냐? 라고 한다면 그것은 아니다. 보통 WSGI 구현체 안에서 앞으로 소개할 ASGI 구현체를 외부 라이브러리를 가져다 사용하듯이 사용하여 비동기 처리가 가능해진다.

2-2. 비동기(asynchronous) 처리가 가능: ASGI

ASGI는 WSGI 와는 다르게 비동기 처리가 가능하여 동시성 구현이 가능하다. 대표적인 ASGI 구현체로는 uvicorn, hypercone, dalphne 등이 있다.

 

여기서 문득 ASGI 와 WSGI 간의 관계가 무엇인지 헷갈릴 수 있다. ASGI 와 WSGI는 서로 간에 상호배타적인 개념은 아니며, 위에서 잠시 언급했듯이 WSGI 구현체 안에서 ASGI 구현체를 사용할 수도 있다. 대표적인 예시로 FastAPI 프레임워크를 사용할 때 공식 문서에서 제안하듯이 WSGI 구현체인 gunicorn을 사용하되 워커로 uvicorn을 가져다 사용할 수 있는 케이스다. 이렇게 ASGI 와 WSGI 간에 호환이 가능한 구체적인 이유는 공식 문서를 참조해보자.

 

마지막으로 정리해보자면 Python에서 웹 통신을 수행할 때의 구조는 크게 아래와 같은 케이스로 구분되어서 구축될 수 있겠다.

 

Python에서 웹 통신 시 서버 구조

 

반응형