블로그 | NGINX

NGINX로 파이썬 성능 극대화하기, 1부: 웹 서빙 및 캐싱

NGINX-F5-수평-검정-유형-RGB의 일부
플로이드 스미스 썸네일
플로이드 스미스
2016년 3월 31일 게시

소개 – NGINX가 Python과 함께 사용되는 방법

Python은 사용하기 쉽고 재밌으며, 소프트웨어 개발을 더 쉽게 만들고, 다른 스크립트 언어보다 런타임 성능이 뛰어나다는 점에서 유명합니다. (하지만 최신 버전인 PHP 7은 Python과 경쟁할 수도 있습니다.)

누구나 자신의 웹사이트와 애플리케이션이 더 빠르게 실행되기를 원합니다. 또한 트래픽이 급증하거나 급증하는 모든 웹사이트는 성능 문제와 다운타임에 취약하며, 이는 종종 가장 바쁜 시간인 최악의 시간에 발생합니다. 또한 거의 모든 웹사이트는 트래픽 양이 꾸준히 증가하든 사용량이 급격히 늘어나든 성능 문제와 다운타임을 겪습니다.

여기서 NGINX와 NGINX Plus가 등장합니다. 그들은 세 가지 방법으로 웹사이트 성능을 개선합니다.

  1. 웹 서버로서 NGINX는 원래 C10K 문제를 해결하기 위해 개발되었습니다. 즉, 10,000개 이상의 동시 연결을 쉽게 지원하기 위해 개발되었습니다. Python 앱의 웹 서버로 NGINX를 사용하면 트래픽이 적을 때에도 웹사이트 속도가 더 빨라집니다. 사용자가 수천 명이면 성능이 훨씬 높아지고 충돌과 다운타임이 줄어들 가능성이 높습니다. NGINX 웹 서버에서 정적 파일 캐싱이나 마이크로 캐싱을 수행할 수도 있지만, 둘 다 별도의 NGINX 역방향 프록시 서버에서 실행하면 더 잘 작동합니다(다음 문단 참조).
  2. 역방향 프록시 서버로 – 현재 애플리케이션 서버 설정 앞에 역방향 프록시 서버로 NGINX를 "넣을" 수 있습니다. NGINX는 웹에 접근하여 애플리케이션 서버에 요청을 전달합니다. 이 "한 가지 이상한 요령"을 사용하면 웹사이트가 더 빠르게 실행되고, 다운타임이 줄어들고, 서버 리소스 소모가 줄어들고, 보안이 향상됩니다. 정적 파일을 역방향 프록시 서버에 캐싱할 수도 있고(매우 효율적), 동적 콘텐츠의 마이크로캐싱을 추가하여 애플리케이션 자체의 부하를 줄이는 등의 작업을 수행할 수도 있습니다.
  3. 여러 애플리케이션 서버에 대한 부하 분산 장치로 사용하려면 역방향 프록시 서버를 배포하는 것으로 시작합니다. 그런 다음 여러 애플리케이션 서버를 병렬로 실행하고 NGINX 또는 NGINX Plus를 사용하여 트래픽 부하를 분산하여 확장합니다. 이런 종류의 배포를 사용하면 트래픽 요구 사항에 맞춰 웹사이트 성능을 쉽게 확장하여 안정성과 가동 시간을 높일 수 있습니다. 지정된 사용자 세션을 동일한 서버에 유지해야 하는 경우 세션 지속성을 지원하도록 로드 밸런서를 구성합니다.

NGINX와 NGINX Plus는 Python 앱용 웹 서버로 사용하든, 역방향 프록시 서버로 사용하든, 부하 분산 장치로 사용하든, 세 가지 목적 모두에 사용하든 다양한 장점을 제공합니다.

2부로 구성된 시리즈의 첫 번째 기사에서는 Python 앱의 성능을 개선하기 위한 5가지 팁을 설명합니다. 여기에는 NGINX와 NGINX Plus를 웹 서버로 사용하는 방법, 정적 파일 캐싱을 구현하는 방법, 애플리케이션에서 생성된 파일의 마이크로 캐싱을 구현하는 방법 등이 포함됩니다. 2부 에서는 NGINX와 NGINX Plus를 역방향 프록시 서버와 여러 애플리케이션 서버의 로드 밸런서로 사용하는 방법을 설명합니다.

팁 1 – Python 성능 병목 현상 찾기

Python 애플리케이션의 성능이 중요한 두 가지 매우 다른 조건이 있습니다. 첫째, 매일 "적당한" 수의 사용자가 있는 경우이고, 둘째, 부하가 큰 경우입니다. 많은 사이트 소유자들은 가벼운 부하 상황에서 성능에 대해 별로 걱정하지 않습니다. 우리의 겸손한 의견으로는, 응답 시간에 대해 10분의 1초마다 땀을 흘려야 할 때입니다. 응답 시간을 밀리초 단위로 줄이는 것은 어렵고 보람 없는 일이지만, 사용자를 더 행복하게 만들고 사업 성과도 더 좋게 만듭니다.

그러나 이 블로그 게시물과 그에 따른 2부에서는 모든 사람이 걱정하는 시나리오, 즉 사이트가 바쁠 때 발생하는 심각한 성능 저하 및 충돌과 같은 성능 문제에 초점을 맞춥니다. 또한, 해커 공격 중 상당수는 사용자 수가 갑자기 급증하는 효과를 모방하며, 사이트 성능을 개선하는 것도 공격에 대처하는 데 중요한 단계인 경우가 많습니다.

Apache HTTP 서버와 같이 사용자당 일정량의 메모리를 할당하는 시스템에서는 사용자를 추가하면 점점 더 많은 사용자가 몰려들어 물리적 메모리가 과부하 상태가 됩니다. 서버가 디스크로 스왑을 시작하고 성능이 급격히 떨어지며 작동이 중단됩니다. 이 블로그 게시물에 설명된 대로 NGINX로 전환하면 이 문제를 해결하는 데 도움이 됩니다.

Python은 일반적으로 다른 스크립팅 언어보다 작업을 수행하는 데 더 많은 메모리를 사용하기 때문에(결과적으로 실행 속도가 더 빠르기 때문에) 메모리 관련 성능 문제가 특히 발생하기 쉽습니다. 따라서 다른 모든 조건이 동일하다면 Python 기반 앱은 다른 언어로 작성된 앱보다 사용자 부하가 적으면 "무너질" 수 있습니다.

앱을 최적화하면 어느 정도 도움이 될 수 있지만, 일반적으로 이는 트래픽 관련 사이트 성능 문제를 해결하는 가장 좋거나 빠른 방법은 아닙니다. 이 블로그 게시물의 단계와 그에 따른 2부는 트래픽 관련 성능 문제를 해결하는 가장 좋고 빠른 방법입니다. 그런 다음 여기에 제시된 단계를 수행한 후에는 꼭 돌아가서 앱을 개선하거나 마이크로서비스 아키텍처를 사용하도록 다시 작성하세요.

팁 2 – 단일 서버 또는 다중 서버 배포 선택

소규모 웹사이트는 단일 서버에 배포하면 잘 작동합니다. 대규모 웹사이트에는 여러 대의 서버가 필요합니다. 하지만 그 사이의 불분명한 영역에 있거나 사이트가 작은 사이트에서 대규모 사이트로 성장하는 경우 흥미로운 선택을 해야 합니다.

단일 서버 배포가 있는 경우 트래픽 급증이나 전체 트래픽의 급격한 증가가 발생하면 상당한 위험에 처하게 됩니다. 확장성은 제한적이며, 이를 해결할 수 있는 방법으로는 앱 개선, 웹 서버를 NGINX로 전환, 더 크고 빠른 서버 확보, 스토리지를 콘텐츠 전송 네트워크(CDN)로 오프로드 등이 있습니다. 이러한 각 옵션을 구현하는 데는 시간이 걸리고, 비용이 들며, 구현 시 버그나 문제가 발생할 위험이 있습니다.

또한 단일 서버 배포의 경우 사이트는 정의상 단일 장애 지점을 가지게 되며 사이트를 오프라인으로 만들 수 있는 문제 중 다수는 빠르고 간단한 해결책이 없습니다.

NGINX와 Python은 웹 서비스, 부하 분산 및 캐싱에서 NGINX의 케이블을 통해 성능을 제공하기 위해 함께 작동합니다.
“애플리케이션 서버 앞에 NGINX를 놓기”

단일 서버 배포에서 서버를 NGINX로 전환하는 경우 NGINX Open Source와 NGINX Plus 중에서 자유롭게 선택할 수 있습니다. NGINX Plus에는 엔터프라이즈급 지원과 추가 기능이 포함되어 있습니다. 라이브 활동 모니터링 과 같은 일부 추가 기능은 단일 서버 배포에 적합하고, 로드 밸런싱세션 지속성 과 같은 다른 기능은 다중 서버 배포에서 NGINX Plus를 역방향 프록시 서버로 사용하는 경우 유용합니다.

모든 것을 고려했을 때, 사이트가 앞으로 오랫동안 작은 규모로 유지될 것이 확실하고 가동 중단이 큰 문제가 되지 않는 한, 단일 서버 배포에는 어느 정도 위험이 있습니다. 다중 서버 배포는 거의 임의로 확장 가능합니다. 단일 장애 지점을 엔지니어링하여 제거할 수 있으며 성능은 원하는 대로 설정할 수 있으며 용량을 빠르게 추가할 수도 있습니다.

팁 3 – 웹 서버를 NGINX로 변경하세요

웹의 초창기에는 "아파치"라는 이름이 "웹 서버"와 동의어였습니다. 하지만 NGINX는 2000년대 초반에 개발되었으며 꾸준히 인기를 얻고 있습니다. 이미 전 세계 1,000, 10,000, 100,000, [ngx_snippet name='proportion-top-sites']에서 1위를 차지한 웹 서버 입니다.

NGINX는 C10K 문제를 해결하기 위해 개발되었습니다. 즉, 주어진 메모리 예산 내에서 10,000개 이상의 동시 연결을 처리해야 합니다. 다른 웹 서버는 각 연결에 대한 메모리 덩어리가 필요하기 때문에, 수천 명의 사용자가 동시에 사이트에 액세스하려고 하면 실제 메모리가 부족해지고 속도가 느려지거나 충돌합니다. NGINX는 각 요청을 개별적으로 처리하고 더 많은 사용자에게 원활하게 확장됩니다. (아래에서 설명하겠지만, 이는 추가적인 목적에도 매우 유용합니다.)

NGINX 아키텍처의 개략적인 개요는 아래와 같습니다.

웹 서비스, 부하 분산 및 캐싱에서 NGINX 케이블을 사용한 Python 구성 지침을 위한 아키텍처
NGINX 아키텍처, 오픈 소스 애플리케이션 아키텍처, 제2권

다이어그램에서 Python 애플리케이션 서버는 백엔드의 애플리케이션 서버 블록에 들어맞으며 FastCGI에서 액세스하는 것으로 표시됩니다. NGINX는 Python을 실행하는 방법을 "모르므로" 이를 실행하는 환경으로의 게이트웨이가 필요합니다. FastCGI는 PHP, Python 및 기타 언어에서 널리 사용되는 인터페이스입니다.

그러나 Python과 NGINX 간 통신에 더 널리 사용되는 방법은 WSGI(Web Server Gateway Interface)입니다. WSGI는 멀티스레드 및 멀티프로세스 환경에서 작동하므로 이 블로그 게시물에 언급된 모든 배포 옵션에서 확장성이 뛰어납니다.

웹 서버로 NGINX로 이동하는 경우 관련 단계에 대한 많은 지원이 제공됩니다.

이 스니펫은 uWSGI와 함께 사용하도록 NGINX를 구성하는 방법을 보여줍니다. 이 경우 Python 프레임워크 Django를 사용하는 프로젝트입니다.

http { # ...
업스트림 django {
서버 127.0.0.1:29000;
}

서버 {
리스닝 80;
서버 이름 myapp.example.com;

루트 /var/www/myapp/html;

위치 / {
인덱스 index.html;
}

위치 /static/ {
별칭 /var/django/projects/myapp/static/;
}

위치 /main {
/etc/nginx/uwsgi_params 포함;
uwsgi_pass django;

uwsgi_param 호스트 $host;
uwsgi_param X-실제 IP $remote_addr;
uwsgi_param X-전달 대상 $proxy_add_x_forwarded_for;
uwsgi_param X-포워드-프로토 $http_x_포워드_프로토;
}
}
}

팁 4 – 정적 파일 캐싱 구현

정적 콘텐츠를 캐싱한다는 것은 자주 변경되지 않는 파일의 사본을 애플리케이션 서버가 아닌 다른 위치에 보관하는 것을 의미합니다. 즉, 몇 시간마다 또는 전혀 변경되지 않을 수 있습니다. 정적 콘텐츠의 대표적인 예로는 웹 페이지의 일부로 표시되는 JPEG 이미지가 있습니다.

정적 파일 캐싱은 애플리케이션 성능을 향상시키는 일반적인 방법이며 실제로 여러 수준에서 발생합니다.

  • 사용자의 브라우저에서
  • 여러 수준의 인터넷 제공자 - 회사 내부 네트워크부터 인터넷 서비스 제공자(ISP)까지
  • 여기서 설명할 웹 서버에서

웹 서버에 정적 파일 캐싱을 구현하면 두 가지 이점이 있습니다.

  • 사용자에게 더 빠른 전달 – NGINX는 정적 파일 캐싱에 최적화되어 있으며 애플리케이션 서버보다 훨씬 빠르게 정적 콘텐츠에 대한 요청을 실행합니다.
  • 애플리케이션 서버의 부하 감소 – 애플리케이션 서버는 캐시된 정적 파일에 대한 요청을 전혀 보지 못합니다. 웹 서버가 이를 충족시키기 때문입니다.

정적 파일 캐싱은 단일 서버 구현으로는 잘 작동하지만 기본 하드웨어는 여전히 웹 서버와 애플리케이션 서버에서 공유됩니다. 웹 서버에 캐시된 파일을 검색하는 하드웨어가 있는 경우(아주 효율적으로 검색하더라도) 해당 하드웨어 리소스를 애플리케이션에서 사용할 수 없어 어느 정도 속도가 느려질 수 있습니다.

브라우저 캐싱을 지원하려면 정적 파일에 대한 HTTP 헤더를 올바르게 설정하세요. HTTP Cache-Control 헤더(특히 max-age 설정 포함), Expires 헤더, Entity 태그를 고려해 보세요. 해당 주제에 대한 좋은 소개는 NGINX Plus 관리자 가이드에서 uWSGI 및 Django를 사용하여 NGINX 및 NGINX Plus를 애플리케이션 게이트웨이로 사용하기를 참조하세요.

다음 코드는 JPEG 파일, GIF, PNG 파일, MP4 비디오 파일, Powerpoint 파일 등 정적 파일을 캐시하도록 NGINX를 구성합니다. www.example.com을 웹 서버의 URL로 바꾸세요.

server { # "www.example.com"을 웹 서버의 URL로 대체합니다.
server_name www.example.com;
root /var/www/example.com/htdocs;
index index.php;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ .php$ {
try_files $uri =404;
include fastcgi_params;
# Python 서버의 소켓 또는 주소와 포트로 대체합니다.
fastcgi_pass unix:/var/run/php5-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
} 

location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg
|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid
|midi|wav|bmp|rtf)$ {
만료 최대;
log_not_found off;
access_log off;
}
}

팁 5 – 마이크로캐싱 구현

마이크로캐싱은 Python, PHP 및 기타 언어를 실행하는 애플리케이션 서버의 성능을 향상시킬 수 있는 엄청난 기회를 활용합니다. 캐싱 목적으로 세 가지 유형의 웹 페이지가 있습니다.

  • 정적 파일 - 팁 4 에 설명된 대로 캐시될 수 있습니다.
  • 애플리케이션에서 생성되고 개인화되지 않은 페이지 - 최신 상태여야 하므로 이런 페이지는 캐시하는 게 별로 의미가 없습니다. 한 가지 예로, 로그인하지 않은 전자상거래 사용자에게 제공되는 페이지가 있습니다(다음 항목 참조). 판매 가능한 제품, 추천 유사 제품 등은 끊임없이 변경될 수 있으므로 최신 페이지를 제공하는 것이 중요합니다. 하지만 10분의 1초 후에 다른 사용자가 나타난다면 이전 사용자와 같은 페이지를 보여주는 것이 괜찮을 수도 있습니다.
  • 애플리케이션에서 생성된 개인화된 페이지 - 이러한 페이지는 사용자별로 다르고 동일한 사용자가 동일한 개인화된 페이지를 두 번 볼 가능성이 낮기 때문에 유용하게 캐시할 수 없습니다. 예를 들어 로그인한 사용자의 전자상거래 페이지는 다른 사용자에게 동일한 페이지를 보여줄 수 없습니다.
NGINX를 사용한 마이크로 캐싱
정적 파일 및 개인화되지 않은 애플리케이션 생성 파일은 캐시될 수 있습니다.

마이크로 캐싱은 위에서 설명한 두 번째 페이지 유형, 즉 애플리케이션에서 생성되고 개인화되지 않은 페이지에 유용합니다. "마이크로"는 짧은 기간을 의미합니다. 사이트에서 1초에 여러 번 같은 페이지를 생성하는 경우 1초만 캐시해도 페이지의 신선도에 크게 해가 되지 않을 수 있습니다. 그러나 이 짧은 캐싱 기간은 특히 트래픽 급증 시 애플리케이션 서버의 부하를 크게 줄일 수 있습니다. 캐시 시간 초과 기간 동안 동일한 콘텐츠가 있는 10개, 20개, 100개 페이지를 생성하는 대신, 주어진 페이지를 한 번만 생성한 다음 해당 페이지를 캐시하여 캐시에서 많은 사용자에게 제공합니다.

그 효과는 어찌나 기적적이던지요. 초당 수많은 요청을 처리할 때는 느린 서버도 정확히 하나의 요청을 처리하면 매우 빨라집니다. (물론 개인화된 페이지도 포함됩니다.) 우리의 오웬 개럿은 마이크로 캐싱의 이점을 구성 코드와 함께 자세히 설명하는 블로그 게시물을 올렸습니다. 1초의 시간 제한으로 프록시 캐시를 설정하는 핵심 변경 사항에는 몇 줄의 구성 코드만 필요합니다.

proxy_cache_path /tmp/cache 키_존=캐시:10m 레벨=1:2 비활성=600s 최대_크기=100m;서버 {
proxy_cache 캐시;
proxy_cache_valid 200 1s;
# ...
}

더 많은 샘플 구성을 보려면 NGINX를 사용한 Python 및 uWSGI 에 관한 Tyler Hicks‑Wright의 블로그를 참조하세요.

결론

1부에서는 단일 서버 Python 구현의 성능을 높이기 위한 솔루션과 단일 서버 구현에 배포하거나 역방향 프록시 서버 또는 별도의 캐싱 서버에서 실행할 수 있는 캐싱에 대해 살펴보았습니다. (캐싱은 별도의 서버에서 더 잘 작동합니다.) 다음 부분 인 2부 에서는 두 개 이상의 서버가 필요한 성능 솔루션에 대해 설명합니다.

애플리케이션에 사용할 수 있는 NGINX Plus 의 고급 기능(지원, 실시간 활동 모니터링, 즉석 재구성 등)을 알아보려면 오늘 무료 30일 평가판을 시작하거나 당사에 문의하여 사용 사례에 대해 논의해 보세요 .


"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."