gunicorn - 아키텍처 설계

hwisaac·2023년 9월 6일
0

gunicorn

목록 보기
8/8

Gunicorn 아키텍처 설계

서버 모델

Gunicorn은 프리포크 워커 모델을 기반으로 합니다. 이 모델은 중앙 마스터 프로세스가 일련의 워커 프로세스를 관리하는 구조를 갖고 있습니다. 마스터 프로세스는 개별 클라이언트에 대해 아무것도 모르며 모든 요청과 응답은 워커 프로세스에서 완전히 처리됩니다.

마스터

마스터 프로세스는 다양한 프로세스 신호를 수신하고 그에 따라 반응하는 간단한 루프로 구성되어 있습니다. 이 루프는 TTIN, TTOU 및 CHLD와 같은 신호를 수신하여 실행 중인 워커 목록을 관리합니다. TTIN과 TTOU는 마스터에게 실행 중인 워커의 수를 증가 또는 감소시키라는 명령을 내립니다. CHLD는 자식 프로세스가 종료되었음을 나타내며 이 경우 마스터 프로세스는 자동으로 실패한 워커를 다시 시작합니다.

동기 워커

가장 기본적이고 기본 워커 유형은 한 번에 하나의 요청을 처리하는 동기 워커 클래스입니다. 이 모델은 오류가 최대 하나의 요청에만 영향을 미치므로 이해하기 가장 간단합니다. 그러나 한 번에 하나의 요청만 처리하기 때문에 어떤 오류든 최대 하나의 요청에만 영향을 미칩니다. 그러나 이 모델은 어떤 가정을 필요로 합니다. 동기 워커는 지속적인 연결을 지원하지 않으며 각 연결은 응답이 전송된 후에 닫힙니다.

비동기 워커

비동기 워커는 Greenlets(이벤트릿 및 지벤트를 통해)을 기반으로 합니다. Greenlets는 Python을 위한 협력적인 멀티 스레딩 구현입니다. 이 워커 클래스는 일반적으로 응용 프로그램을 변경하지 않고 사용할 수 있습니다. 그러나 완전한 그린릿 지원을 위해서는 응용 프로그램을 조정해야 할 수 있습니다. 예를 들어 Gevent와 Psycopg를 사용할 때는 psycogreen이 설치되고 설정되어 있는지 확인하는 것이 좋습니다. 그러나 일부 응용 프로그램은 원래의 패치되지 않은 동작에 의존하기 때문에 전혀 호환되지 않을 수 있습니다.

Gthread 워커

Gthread 워커는 스레드 기반 워커입니다. 이 워커는 메인 루프에서 연결을 수락하고 스레드 풀에 연결 작업을 추가합니다. Keepalive 연결은 이벤트를 대기하는 루프로 다시 넣으며 일정 시간 동안 이벤트가 발생하지 않으면 연결이 닫힙니다.

Tornado 워커

Tornado 워커 클래스도 있으며 Tornado 프레임워크를 사용하여 애플리케이션을 작성하는 데 사용할 수 있습니다. 그러나 Tornado 워커를 사용하여 WSGI 애플리케이션을 서비스하는 것은 권장되지 않습니다.

AsyncIO 워커

이 워커는 Python 3과 호환됩니다. 응용 프로그램을 aiohttp의 web.Application API를 사용하도록 포팅할 수 있으며 aiohttp.worker.GunicornWebWorker 워커를 사용할 수 있습니다.

워커 유형 선택

기본 동기 워커는 응용 프로그램이 CPU 및 네트워크 대역폭 측면에서 리소스에 제한된 것으로 가정합니다. 이는 응용 프로그램이 정의되지 않은 시간이 걸리는 작업을 수행하지 않아야 함을 의미합니다. 예를 들어 인터넷에 대한 요청이 정의되지 않은 시간이 걸리는 작업입니다. 어느 시점에서는 외부 네트워크에서 서버로 데이터를 조금씩 전달하여 부하를 생성하면 클라이언트가 서버를 쌓을 것입니다. 따라서 이러한 의미에서 외부 API로 요청을 만드는 모든 웹 애플리케이션은 비동기 워커에서 이점을 얻을 것입니다.

이 리소스 바인딩 가정은 우리가 기본 구성 Gunicorn 앞에 버퍼링 프록시를 제공하는 이유입니다. 동기 워커를 인터넷에 노출하면 DOS(서비스 거부) 공격이 서버로 데이터를 누출하는 작은 부하를 만들어 쉽게 발생할 수 있습니다. 이러한 유형의 부하 예로 "Hey"가 있습니다.

비동기 워커가 필요한 행동 예:

  • 긴 블로킹 호출을 하는 응용 프로그램(예: 외부 웹 서비스 호출)

  • 인터넷에 직접 요청을 서비스

  • 스트리밍 요청 및 응답

  • 롱 폴링

  • 웹 소켓

  • 혜성

워커 수 결정

클라이언트 수에 따라 워커 수를 확장하지 마십시오. Gunicorn은 수백 개 또는 수천 개의 요청을 처리하는 데 4-12개의 워커 프로세스만 필요로 합니다.

Gunicorn은 요청 처리 시 운영 체제가 제공하는 모든 로드 밸런싱을 의존합니다. 일반적으로 (2 x $num_cores) + 1을 워커를 시작하는 수로 권장합니다. 과학적으로 엄밀하지는 않지만 이 공식은 주어진 코어에 대해 하나의 워커가 소켓에서 읽거나 쓸 때 다른 워커가 요청을 처리한다는 가정에 기반하고 있습니다.

물론 하드웨어와 응용 프로그램에 따라 최적의 워커 수가 다를 것입니다. 권장 사항은 위의 추측부터 시작하고 응용 프로그램이 부하를 받을 때 TTIN 및 TTOU 신호를 사용하여 튜닝하는 것입니다.

항상 기억하세요. 워커가 너무 많다는 것이 있습니다. 어느 시점 이후에 워커 프로세스는 시스템 리소스를 충분히 낭비하여 전체 시스템 처리량을 줄일 것입니다.

스레드 수 결정

Gunicorn 19부터 스레드 옵션을 사용하여 여러 스레드에서 요청을 처리할 수 있습니다. 스레드를 사용하면 워커 타임아웃보다 요청이 길어질 수 있지만 마스터 프로세스에게 얼어 있지 않으며 종료되지 않아야 함을 알리는 이점이 있습니다. 시스템에 따라 여러 스레드, 여러 워커 프로세스 또는 일부 혼합을 사용하는 것이 최상의 결과를 얻을 수 있습니다. 예를 들어 CPython은 각각 다르게 구현되기 때문에 스레드를 사용할 때 Jython과 같이 잘 수행되지 않을 수 있습니다. 스레드 대신 프로세스 대신 스레드를 사용하는 것은 Gunicorn의 메모리 풋 프린트를 줄이는 좋은 방법이며 응용 프로그램 코드는 워커 프로세스에서만 로드되며 마스터 프로세스에서만로드되지 않습니다 (preload 설정을 사용할 때와 달리).

참고

Python 2.x의 경우 이 기능을 사용하려면 'futures' 패키지를 설치해야 합니다.

0개의 댓글