NGINX로 Python 성능 극대화하기, 1부: 웹 서비스 및 캐싱
NGINX와 NGINX Plus는 Python 애플리케이션의 웹 서버, Reverse Proxy 서버, Load Balancer 또는 이 세 가지 용도로 모두 사용할 수 있는 이점을 제공합니다.
Python은 쉽고 재미있게 사용할 수 있고, 소프트웨어 개발이 쉬우며, 다른 스크립트 언어를 능가하는 런타임 성능으로 유명합니다. (최신 버전의 PHP인 PHP 7은 Python의 성능을 뛰어넘을 수 있습니다.) 하지만, PHP 7의 런타임 성능은 Python의 성능에 미치지 못합니다.
누구나 자신의 웹사이트와 애플리케이션이 더 빠르게 실행되기를 원합니다. 또한 트래픽이 증가하거나 트래픽이 급증하는 모든 웹사이트는 성능 문제와 Downtime에 취약하며, 이는 최악의 상황, 즉 가장 바쁜 시간에 발생하는 경우가 많습니다. 또한 트래픽이 꾸준히 증가하거나 사용량이 급격히 증가하는 경우 거의 모든 웹사이트가 성능 문제와 Downtime을 겪습니다.
이것이 바로 NGINX와 NGINX Plus의 역할입니다. 세 가지 방식으로 웹사이트 성능을 개선합니다.
- 웹 서버로서 – NGINX는 원래 C10K 문제, 즉 10,000명 이상의 동시 연결을 쉽게 지원하기 위해 개발되었습니다. NGINX를 Python 애플리케이션의 웹 서버로 사용하면 트래픽이 적은 경우에도 웹사이트의 속도가 빨라집니다. 수천 명의 사용자가 있는 경우, 훨씬 더 높은 성능, 더 적은 충돌, 더 적은 Downtime을 제공하는 것이 거의 확실합니다. 정적 파일 캐싱이나 Microcaching을 NGINX 웹 서버에서 수행할 수도 있지만, 두 가지 모두 별도의 NGINX Reverse Proxy 서버에서 실행할 때 더 잘 작동합니다.
- Reverse Proxy 서버로 – 현재 애플리케이션 서버 설정 앞에 Reverse Proxy 서버로 NGINX를 배치할 수 있습니다. NGINX는 웹을 향하여 애플리케이션 서버로 요청을 전달합니다. 이 “one weird trick”을 사용하면 웹사이트가 더 빠르게 실행되고, Downtime이 줄어들고, 서버 리소스를 덜 소비하며, 보안이 향상됩니다. 또한 Reverse Proxy 서버에서 정적 파일을 캐시하고, 동적 콘텐츠의 Microcaching을 추가하여 애플리케이션 자체의 부하를 줄이는 등의 작업을 수행할 수 있습니다.
- 여러 애플리케이션 서버를 위한 Load Balancer 역할 – Reverse Proxy 서버를 배포하는 것으로 시작하세요. 그런 다음 여러 애플리케이션 서버를 병렬로 실행하고 NGINX 또는 NGINX Plus를 사용하여 서버 간 트래픽 Load Balancning을 수행하여 확장하세요. 이러한 배포 방식을 사용하면 트래픽 요구 사항에 따라 웹사이트의 성능을 쉽게 확장하여 안정성과 가동 시간을 높일 수 있습니다. 특정 사용자 세션이 동일한 서버에 유지되어야 하는 경우 세션 지속성을 지원하도록 Load Balancer를 구성하세요.
목차
1. 팁 1 – Python 성능 병목 현상 찾기
2. 팁 2 – 단일 서버 또는 다중 서버 배포 선택
3. 팁 3 – 웹 서버를 NGINX로 변경하기
4. 팁 4 – 정적 파일 캐싱 구현하기
5. 팁 5 – Microcaching 구현
6. Python 성능 극대화 1부 결론
1. 팁 1 – Python 성능 병목 현상 찾기
Python 애플리케이션의 성능이 중요한 두 가지 조건이 있는데, 첫째는 매일 “적당한” 수의 사용자가 있는 경우이고, 둘째는 부하가 많은 경우입니다. 많은 사이트 소유자가 가벼운 부하 상태에서는 성능에 대해 너무 걱정하지 않는데, 당사의 겸손한 견해로는 응답 시간의 10초마다 땀을 흘려야 한다고 합니다. 응답 시간을 ms 단위로 단축하는 것은 어렵고 보람 없는 일이지만, 사용자 만족도를 높이고 비즈니스 성과를 개선할 수 있습니다.
Apache HTTP 서버와 같이 사용자당 일정량의 메모리를 할당하는 시스템에서는 사용자를 추가하면 점점 더 많은 사용자가 몰리면서 물리적 메모리에 과부하가 걸리게 됩니다. 서버가 디스크로 스왑을 시작하고 성능이 급격히 떨어지며 성능 저하와 충돌이 이어집니다. 이 포스트에 설명된 대로 NGINX로 이전하면 이 문제를 해결하는 데 도움이 됩니다.
Python은 일반적으로 다른 스크립트 언어보다 더 많은 메모리를 사용하여 작업을 수행하기 때문에 메모리 관련 성능 문제가 발생하기 쉽습니다. 따라서 다른 모든 조건이 동일하다면 Python 기반 애플리케이션은 다른 언어로 작성된 애플리케이션보다 사용자 부하가 적을 때 성능이 저하될 수 있습니다.
2. 팁 2 – 단일 서버 또는 다중 서버 배포 선택
소규모 웹사이트는 단일 서버에 배포해도 정상적으로 작동합니다. 대규모 웹사이트는 여러 대의 서버가 필요합니다. 하지만 그 사이에 있는 애매한 영역에 있거나 소규모 사이트에서 대규모 사이트로 성장하고 있다면 몇 가지 흥미로운 선택을 할 수 있습니다.
단일 서버를 배포하는 경우 트래픽이 급증하거나 전체 트래픽이 급격히 증가하는 경우 상당한 위험에 처하게 됩니다. 따라서 애플리케이션 개선을 비롯해 웹 서버를 NGINX로 전환하거나, 더 크고 빠른 서버를 확보하거나, 스토리지를 CDN(Content Delivery Network)으로 Offload하는 등의 방법으로 해결할 수 있는 확장성이 제한됩니다. 이러한 각 옵션은 구현하는 데 시간이 걸리고 비용이 발생하며 구현 시 Bug나 문제가 발생할 위험이 있습니다.
또한 단일 서버 배포의 경우 사이트에는 기본적으로 단일 장애 지점이 존재하며, 사이트를 오프라인 상태로 만들 수 있는 많은 문제에는 빠르고 간단한 해결책이 없습니다.

애플리케이션 서버 앞에 NGINX 배치
단일 서버 배포에서 서버를 NGINX로 전환하는 경우, NGINX Open Source와 NGINX Plus 중에서 자유롭게 선택할 수 있습니다. NGINX Plus에는 엔터프라이즈급 지원과 추가 기능이 포함되어 있습니다. 실시간 활동 모니터링과 같은 일부 추가 기능은 단일 서버 배포와 관련이 있으며, Load Balancing 및 세션 지속성과 같은 다른 기능은 다중 서버 배포에서 NGINX Plus를 Reverse Proxy 서버로 사용하는 경우에 유용합니다.
앞으로 오랫동안 사이트를 소규모로 유지할 것이 확실하고 다운타임이 크게 걱정되지 않는다면 단일 서버 배포는 어느 정도 안전하지만, 그렇지 않은 경우라면 단일 서버 배포가 위험할 수 있습니다. 반면 다중 서버 배포는 거의 임의로 확장할 수 있으며, 단일 장애 지점을 설계할 수 있고 용량을 빠르게 추가할 수 있는 기능을 통해 원하는 대로 성능을 조정할 수 있습니다.
3. 팁 3 – 웹 서버를 NGINX로 변경하기
웹 초창기에는 “Apache”라는 이름이 “웹 서버”와 동의어였습니다. 하지만 2000년대 초반에 개발된 NGINX는 꾸준히 인기를 얻고 있으며, 현재 전 세계에서 사용량이 가장 많은 웹사이트 100,000개 사이트에서 1위 웹 서버로 사용되고 있습니다.
NGINX는 C10K 문제, 즉 주어진 메모리 예산 내에서 10,000개 이상의 동시 연결을 처리하는 문제를 해결하기 위해 개발되었습니다. 다른 웹 서버는 각 연결마다 메모리 Chunk가 필요하기 때문에 수천 명의 사용자가 동시에 사이트에 액세스하려고 할 때 물리적 메모리가 부족해져 속도가 느려지거나 충돌이 발생합니다. NGINX는 각 요청을 개별적으로 처리하고 더 많은 사용자에 맞게 부드럽게 확장할 수 있습니다. (아래에서 설명하듯이 다른 용도로도 훌륭하게 사용할 수 있습니다.)
NGINX 아키텍처의 대략적인 개요는 아래와 같습니다.

다이어그램에서 Python 애플리케이션 서버는 Backend의 애플리케이션 server 블록에 적합하며, FastCGI가 액세스하는 것으로 표시됩니다. NGINX는 Python을 실행하는 방법을 알지 못하므로 이를 실행할 수 있는 환경에 대한 Gateway가 필요합니다. FastCGI는 PHP, Python 및 기타 언어에 널리 사용되는 인터페이스입니다.
그러나 Python과 NGINX 간의 통신을 위해 더 많이 사용되는 선택은 Web Server Gateway Interface(WSGI)입니다. WSGI는 멀티 스레드 및 멀티 프로세스 환경에서 작동하므로 이 포스트에 언급된 모든 배포 옵션에 걸쳐 잘 확장됩니다.
웹 서버로 NGINX로 이전하는 경우 이와 관련된 단계에 대한 다양한 지원이 제공됩니다.
- Gunicorn 구성 – NGINX와 함께 사용할 수 있는 대중적인 WSGI 서버인 “Green Unicorn”.
- uWSGI 구성 – 또 다른 많이 사용되는 WSGI 서버로, NGINX와 함께 사용할 수 있습니다. uWSGI는 NGINX에 대한 직접적인 지원을 포함합니다.
- uWSGI, NGINX 및 Django 사용 – 대중적으로 사용되는 Python 웹 프레임워크입니다.
이 Snippet은 파이썬 프레임워크 Django를 사용하는 프로젝트에서 uWSGI와 함께 사용할 수 있도록 NGINX를 구성하는 방법을 보여 줍니다.
http {
# ...
upstream django {
server 127.0.0.1:29000;
}
server {
listen 80;
server_name myapp.example.com;
root /var/www/myapp/html;
location / {
index index.html;
}
location /static/ {
alias /var/django/projects/myapp/static/;
}
location /main {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
}
}
}
4. 팁 4 – 정적 파일 캐싱 구현하기
정적 콘텐츠 캐싱은 자주 변경되지 않는 파일의 복사본을 애플리케이션 서버가 아닌 다른 위치에 보관하는 것을 의미합니다. 정적 콘텐츠의 일반적인 예로는 웹 페이지의 일부로 표시되는 JPEG 이미지가 있습니다.
정적 파일 캐싱은 애플리케이션 성능을 향상시키는 일반적인 방법이며 실제로 여러 Level에서 이루어집니다.
- 사용자의 브라우저에서
- 여러 Level의 인터넷 제공 업체에서 – 회사 내부 네트워크에서 Internet Service Provider(ISP)로의 전환
- 웹 서버에서는 다음과 같이 설명합니다.
웹 서버에서 정적 파일 캐싱을 구현하면 두 가지 이점이 있습니다.
- 사용자에게 더 빠르게 제공 – NGINX는 정적 파일 캐싱에 최적화되어 있으며 애플리케이션 서버보다 훨씬 빠르게 정적 콘텐츠에 대한 요청을 실행합니다.
- 애플리케이션 서버 부하 감소 – 웹 서버가 캐시 된 정적 파일에 대한 요청을 처리하기 때문에 애플리케이션 서버는 캐시 된 정적 파일에 대한 요청조차 인식하지 못합니다.
정적 파일 캐싱은 단일 서버 구현에서 잘 작동하지만 기본 하드웨어는 여전히 웹 서버와 애플리케이션 서버가 공유합니다. 웹 서버의 하드웨어가 캐시된 파일을 검색하느라 바쁘면 애플리케이션에서 해당 하드웨어 리소스를 사용할 수 없으므로 속도가 어느 정도 느려질 수 있습니다.
브라우저 캐싱을 지원하려면 정적 파일에 대해 HTTP 헤더를 올바르게 설정하세요. HTTP Cache-Control 헤더, Expires 헤더 및 Entity 태그를 고려하세요.
다음 코드는 JPEG 파일, GIF, PNG 파일, MP4 비디오 파일, 파워포인트 파일 등을 포함한 정적 파일을 캐시하도록 NGINX를 구성합니다. www.example.com
을 본인의 웹 서버 URL로 바꿉니다.
server {
# substitute your web server's URL for "www.example.com"
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;
# substitute the socket, or address and port, of your Python server
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)$ {
expires max;
log_not_found off;
access_log off;
}
}
5. 팁 5 – Microcaching 구현
Microcaching은 Python, PHP 및 기타 언어를 실행하는 애플리케이션 서버의 성능을 개선할 수 있는 큰 기회를 활용합니다. 캐싱 목적으로 사용되는 웹 페이지에는 세 가지 유형이 있습니다.
- 정적 파일 – 팁 4에 설명된 대로 캐시할 수 있습니다.
- 애플리케이션 생성, Non‑Personalized 페이지 – 이러한 페이지는 최신 상태여야 하므로 캐싱 하는 것은 일반적으로 적합하지 않습니다. 예를 들어 로그인하지 않은 사용자에게 전달되는 페이지는 사용 가능한 제품, 추천 유사 제품 등이 계속 변경될 수 있으므로 새로운 페이지를 제공하는 것이 중요합니다. 그러나 10초 후에 다른 사용자가 나타나면 이전 사용자와 동일한 페이지를 표시해도 괜찮을 수 있습니다.
- 애플리케이션 생성, Personzlized 페이지 – 이러한 페이지는 사용자마다 다르기 때문에 캐시 할 수 없으며, 동일한 사용자가 동일한 맞춤 페이지를 두 번 볼 가능성은 거의 없습니다. 예를 들어 로그인한 사용자를 위한 페이지의 경우 다른 사용자에게 동일한 페이지를 표시할 수 없습니다.

Microcaching은 위에서 설명한 두 번째 페이지 유형, 즉 애플리케이션 생성, Non‑Personalized 페이지에 유용합니다. ” Micro”는 짧은 기간을 의미합니다. 사이트에서 동일한 페이지를 초당 여러 번 생성하는 경우 1초 동안 캐싱 해도 페이지의 최신 상태가 크게 손상되지 않을 수 있습니다. 하지만 이 짧은 캐싱 기간은 특히 트래픽이 급증할 때 애플리케이션 서버의 부하를 크게 증가시킬 수 있습니다. 캐시 제한 시간 동안 동일한 콘텐츠의 페이지를 10개, 20개, 100개 생성하는 대신 특정 페이지를 한 번만 생성하면 해당 페이지가 캐시에 저장되어 캐시를 통해 많은 사용자에게 제공됩니다.
proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;
server {
proxy_cache cache;
proxy_cache_valid 200 1s;
# ...
}
더 많은 샘플 구성에 대한 자세한 내용은 Tyler Hicks-Wright’s의 블로그에서 NGINX를 사용한 Python 및 uWSGI를 참조하세요.
6. Python 성능 극대화 1부 결론
1부에서는 단일 서버 구현의 성능을 향상시키기 위한 솔루션과 단일 서버 구현에 배포하거나 Reverse Proxy 서버 또는 별도의 캐싱 서버에서 실행할 수 있는 캐싱에 대해 살펴봤습니다.
NGINX Plus를 직접 사용해 보거나 테스트해 보려면 지금 30일 무료 평가판을 신청하거나 사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.
댓글을 달려면 로그인해야 합니다.