9월부터 11월까지 간단한 사이드 프로젝트를 진행하기로 했다. 어렵지 않은 난이도에 평소에 접해보고자 했던 내용들을 접할 수 있어서 참여하기로 결정했다. 막 어제 개발 환경 셋팅을 끝냈다. 이번 기회에 내가 새로 배울 수 있는 내용은 1. 앱 개발자와 협업 (React Native)
2. Firebase Cloud Messaging를 기반으로 한 푸시 메시지 큐 시스템 활용
정도가 될 것 같다.
여기에 더불어 AWS ElasticBeanstalk으로 인스턴스를 띄우지 않고 EC2를 이용해 서버 인스턴스를 구성했다. 이번 기회에 Beanstalk 콘솔이 아닌 ubuntu-docker 환경에서 nginx같은 웹서버 소프트웨어를 직접 설정-운영 해보는 기회로 삼고자 했다.
위와 같은 구조로 서버를 구성했다.
(nginx + FastAPI (+ uvicorn))
은 EC2 인스턴스 내 Docker 컨테이너로 감싸 운영한다. 항상 Elastic Beanstalk의 콘솔 환경에서 서버를 운영하는 것에 익숙해져있었다. 하지만 내손으로 직점 nginx의 config 파일을 수정해가며 서버 설정을 하다보니, 자연스레 nginx와 FastAPI가 어떻게 상호작용 하는지에 대해 깊게 알아보고 싶어졌다.
reverse proxy
)해 외부(client)에 응답을 전달한다. nginx는 외부(클라이언트)의 요청을 듣고(listen), 이를 어떻게 처리해야하는지를 "다른 작업자에게 알려주기만 하는" 방식으로 작동된다.
이를 Event Driven 방식이라고 하며, 이벤트를 생성하고 소비하는 주체가 분리되는 Producer-Consumer Pattern 을 생각하면 쉽다.
반면 apache는 요청에 대한 작업을 apahce가 점유하는 프로세스나 스레드가 직접 수행한다.
쉽게말해 nginx는 비동기로 작업연산을 다른 worker에 "전달"만 하고 바로 다른 작업연산을 받는(nonblocking io)
하는 방식이라면, apache는 연산 작업을 직접 책임지고 수행(blocking io)
하는 방식이라고 볼 수 있다. 당연히 nginx식 처리는 더 많은 연산을 빠르게 처리할 수 있고, apache식 처리는 연산을 안정적이게 처리할 수 있게 된다.
위의 과정을 거쳐 nginx는 외부(client)로 부터의 요청을 event loop에 등록에 등록한다. 이제 이 event loop에 등록된 작업을 수행할 작업자가 필요하다. python으로 작성된 웹서버에서 이를 수행하는 것이 바로 Web Server Gateway Interface
즉, WSGI라고 부르는 것이다. 이러한 WSGI에는 대표적으로 gunicorn이 있는데, FastAPI에서는 이를 Async 방식으로 튜닝한 uvicorn
이라는 것을 ASGI(Asynchronous Server Gateway Interface
)로 사용한다.
nginx가 event loop에 등록해놓은 요청들을 WSGI(ASGI)의 작업자들이 가져가 처리하고, 결과를 응답하면 nginx가 이 결과를 다시 클라이언트에 돌려주는 방식이다.
쉽게 말해 nginx는 서버의 맨 앞에서, 외부(client)의 요청을 컨트롤하는 역할을 한다. 다만, 이러한 역할은 WSGI(ASGI) 자체적으로도 수행할 수 있다.
WSGI(ASGI) 만으로도 요청을 받을 수 있고, 파이썬이 필요한 연산을 하게 지시할 수 있기 때문이다.
간단히 예를 들자면, FastAPI 작업시 흔히 로컬에서 사용하는
uvicorn main:app
명령어로만 서버를 띄어도 외부의 요청을 처리할 수 있는 원리와 같다.
uvicorn 공식 문서에서도 nginx 뒤에서 배포하는 가이드와, nginx 없이 배포하는 가이드를 모두 설명한다.
실제로 동시 접속자수 700명 미만인 경우에 nginx 없이 WSGI (gunicorn) 만으로도 서버 운영이 가능하다고 한다.
(로컬 ip: 172.18.0.2)
가 아닌, 실제 클라이언트의 정보(클라이언트 ip: 61.43.54.2)
를 알기 위해서는, nginx가 클라이언트의 요청을 전달할 때 임의의 헤더에 원본 요청(클라이언트 요청)의 정보를 심어줘야 한다. #nginx.conf
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
이렇게 nginx를 설정해주면, 클라이언트의 IP주소를 X-Real_IP라는 헤더에 심어 FastAPI에 전달하게 된다.
즉, WSGI나 ASGI로도 서버를 돌릴 수 있지만, 이는 말그대로 요청을 전송하는 Gateway
역할에 불과하고, 다양한 보안-성능상의 이점을 얻으려면 nginx와 같은 웹서버 소프트웨어의 도움이 필수적이다.
Web Server Gateway Interface (WSGI // ASGI)
로도 서버를 운영할 수 있다. 다음엔 nginx의 worker와 eventloop <> WSGI(ASGI)의 worker의 연산 처리 과정에 대해 연구해봐야겠다.
훌륭하십니다.
블록체인 관련글도 써주세요!