Nginx와 UWSGI를 이용한 웹 서버 구축

Tengine은 타오바오(淘宝)에서 시작한 웹 서버 프로젝트입니다. Nginx를 기반으로 대규모 트래픽 웹사이트의 요구사항에 맞춰 여러 고급 기능과 특징이 추가되었습니다. Tengine의 성능과 안정성은 타오바오, 티몰(天猫)과 같은 대형 웹사이트에서 검증되었습니다. 궁극적인 목표는 효율적이고 안정적이며 안전한 웹 플랫폼을 구축하는 것입니다.

Nginx의 고급 버전으로 이해할 수 있습니다.

설치 요구사항

Nginx 설치에는 다음의 의존성 환경이 사전에 설치되어 있어야 합니다:

# GCC 설치
Nginx 설치 전 소스 코드를 컴파일해야 하며, 이는 GCC 환경에 의존합니다. 설치되어 있지 않다면 다음과 같이 설치합니다:
yum install gcc

# PCRE pcre-devel 설치
PCRE(Perl Compatible Regular Expressions)은 Perl 라이브러리로, Perl 호환 정규 표현식 라이브러리를 포함합니다. Nginx의 http 모듈은 pcre를 사용하여 정규 표현식을 파싱하므로 Linux에 pcre 라이브러리를 설치해야 합니다. pcre-devel은 pcre를 사용한 2차 개발 라이브러리이며, Nginx도 이 라이브러리가 필요합니다:
yum install -y pcre pcre-devel

# zlib 설치
zlib 라이브러리는 다양한 압축 및 압축 해제 방법을 제공하며, Nginx는 zlib를 사용하여 http 패킷 내용을 gzip으로 압축합니다. 따라서 CentOS에 zlib 라이브러리를 설치해야 합니다:
yum install -y zlib zlib-devel

# OpenSSL 설치
OpenSSL은 강력한 보안 소켓 계층 암호 라이브러리로, 주요 암호 알고리즘, 일반적인 키 및 인증서 캡슐화 관리 기능 및 SSL 프로토콜을 포함하며, 테스트 또는 기타 목적으로 사용할 수 있는 풍부한 애플리케이션을 제공합니다. Nginx는 http 프로토콜뿐만 아니라 https(ssl 프로토콜을 통해 전송되는 http)도 지원하므로 CentOS에 OpenSSL 라이브러리를 설치해야 합니다:

설치 주의사항

# 구성 및 컴파일 설치 - nginx 상태 모니터링 기능과 SSL 기능 활성화, 더 많은 기능은 공식 문서 참조 http://nginx.org/en/docs/configure.html
./configure --prefix=/opt/nginx1-12/ --with-http_ssl_module --with-http_stub_status_module
make && make install

# nginx 시작 - sbin 디렉토리로 이동하여 nginx 시작 명령 찾기
cd sbin
./nginx  # 시작
./nginx -s stop  # 종료
./nginx -s reload  # 구성 파일만 다시 읽고 부드럽게 재시작

# 설치 후 접속 가능 여부 확인
netstat -tunlp |grep 80
curl -I 127.0.0.1
# 접속이 안 된다면 selinux, iptables 확인

Nginx 디렉토리 구조

Nginx 기본 사이트는 Nginx 디렉토리의 html 폴더이며, 이는 nginx.conf에서 확인할 수 있습니다. 웹사이트 비즈니스 데이터를 배포하려면 개발된 프로그램 전체를 html 디렉토리에 배치하기만 하면 됩니다.

이 구성 파일은 전역 블록, 이벤트 블록 및 http 블록 세 부분으로 구성됩니다. http 블록에는 http 전역 블록과 여러 server 블록이 포함됩니다. 각 server 블록에는 server 전역 블록과 여러 location 블록이 포함될 수 있습니다.

location / {
    deny ip 또는 네트워크 대역;  # 접속 거부할 IP
    root html;  # 기본 사이트 html 폴더, 즉 /opt/nginx1-12/html/ 폴더의 내용
    index index.html index.htm;  # 사이트 기본 페이지 파일명은 index.html
}
  • conf: nginx 모든 구성 파일이 저장된 디렉토리, 주요 파일은 nginx.conf
  • html: nginx 기본 사이트가 저장된 디렉토리, 예: index.html, error.html 등
  • logs: nginx 기본 로그가 저장된 디렉토리, 예: error.log, access.log
  • sbin: nginx 주 명령이 저장된 디렉토리, sbin/nginx

Nginx 주 구성 파일 분석

Nginx 주 구성 파일 /etc/nginx/nginx.conf은 순수 텍스트 형식의 파일이며, 전체 구성 파일은 블록 형식으로 조직됩니다. 일반적으로 각 블록은 중괄호 {} 쌍으로 시작과 끝을 표시합니다.

Nginx 구성 파일 상세 설명

# Nginx 실행 사용자 및 그룹 정의
user www www;

# nginx 프로세스 수, CPU 총 코어 수와 동일하게 설정하는 것이 좋습니다.
worker_processes 8;

# 전역 오류 로그 정의 유형, [ debug | info | notice | warn | error | crit ]
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;

# 프로세스 pid 파일
pid /usr/local/nginx/logs/nginx.pid;

# 프로세스가 열 수 있는 최대 디스크립터 수 지정
# 작업 모드 및 연결 수 상한
# 이 명령은 nginx 프로세스가 열 수 있는 최대 파일 디스크립터 수를 지정합니다. 이론적 값은 최대 열 수 파일 수(ulimit -n)와 nginx 프로세스 수를 나눈 값이어야 하지만, nginx 요청 할당이 고르지 않으므로 ulimit -n 값과 일치하는 것이 좋습니다.
# 현재 Linux 2.6 커널에서 파일 열기 수를 65535로 설정하면 worker_rlimit_nofile도 65535로 설정해야 합니다.
# 이는 nginx 스케줄링 시 요청을 프로세스에 할당하는 것이 고르지 않기 때문입니다. 따라서 10240로 설정하면 총 동시 접속 수가 3-4만에 달할 경우 프로세스가 10240을 초과할 수 있으며, 이때 502 오류가 반환됩니다.
worker_rlimit_nofile 65535;

events {
    # 참조 이벤트 모델, use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll 모델
    # Linux 2.6 이상 버전 커널의 고성능 네트워크 I/O 모델이며, Linux는 epoll을 권장합니다. FreeBSD에서 실행 중이면 kqueue 모델을 사용합니다.
    use epoll;

    # 단일 프로세스 최대 연결 수(최대 연결 수=연결 수*프로세스 수)
    # 하드웨어에 맞게 조정하고, 앞의 작업 프로세스와 함께 사용하며, 가능한 한 크게 설정하지만 CPU 사용률이 100%가 되지 않도록 합니다. 각 프로세스가 허용하는 최대 연결 수입니다. 이론적으로 각 nginx 서버의 최대 연결 수는 worker_connections * worker_processes입니다.
    worker_connections 65535;

    # keepalive 타임아웃 시간
    keepalive_timeout 60;

    # 클라이언트 요청 헤더 버퍼 크기. 시스템 페이지 크기에 따라 설정할 수 있으며, 일반적으로 요청 헤더 크기는 1k를 초과하지 않습니다. 하지만 일반 시스템 페이지 크기는 1k보다 크므로 페이지 크기로 설정하는 것이 좋습니다. 페이지 크기는 getconf PAGESIZE 명령으로 얻을 수 있습니다.
    client_header_buffer_size 4k;

    # 이것은 열린 파일에 대한 캐시를 지정하며, 기본적으로 활성화되지 않습니다. max는 캐시 수를 지정하고, inactive는 얼마나 오랫동안 요청되지 않은 후 캐시를 삭제할지 지정합니다.
    open_file_cache max=65535 inactive=60s;

    # 캐시의 유효한 정보를 얼마나 자주 확인할지 지정합니다.
    open_file_cache_valid 80s;

    # open_file_cache 명령의 inactive 매개변수 시간 내 파일의 최소 사용 횟수. 이 숫자를 초과하면 파일 설명자는 캐시에서 계속 열린 상태로 유지됩니다.
    open_file_cache_min_uses 1;

    # 파일을 검색할 때 캐시 오류를 기록할지 여부를 지정합니다.
    open_file_cache_errors on;
}

# http 서버 설정, 역방향 프록시 기능을 사용하여 로드 밸런싱 지원
http {
    # 파일 확장자와 파일 유형 매핑 테이블
    include mime.types;

    # 기본 파일 유형
    default_type application/octet-stream;

    # 기본 인코딩
    charset utf-8;

    # 서버 이름 해시 테이블 크기
    # 서버 이름 해시 테이블은 server_names_hash_max_size 및 server_names_hash_bucket_size 명령으로 제어됩니다. hash bucket 크기는 항상 해시 테이블 크기와 같으며, 일반적으로 프로세서 캐시 크기의 배수입니다. 메모리에서 접근 횟수를 줄인 후 프로세서에서 해시 테이블 키 값을 찾는 속도를 높일 수 있습니다. hash bucket 크기가 프로세서 캐시 크기와 같으면 키를 찾을 때 최악의 경우 메모리에서 2번 조회하게 됩니다. 첫 번째는 저장 단위 주소를 결정하고, 두 번째는 저장 단위에서 키 값을 찾는 것입니다. 따라서 Nginx에서 hash max size 또는 hash bucket size를 늘리라는 메시지가 표시되면 첫 번째 매개변수 크기를 늘리는 것이 우선입니다.
    server_names_hash_bucket_size 128;

    # 클라이언트 요청 헤더 버퍼 크기. 이는 시스템 페이지 크기에 따라 설정할 수 있으며, 일반적으로 요청 헤더 크기는 1k를 초과하지 않습니다. 하지만 일반 시스템 페이지 크기는 1k보다 크므로 페이지 크기로 설정하는 것이 좋습니다. 페이지 크기는 getconf PAGESIZE 명령으로 얻을 수 있습니다.
    client_header_buffer_size 32k;

    # 클라이언트 요청 헤더 버퍼 크기. nginx는 기본적으로 client_header_buffer_size 버퍼를 사용하여 헤더 값을 읽습니다. 헤더가 너무 크면 large_client_header_buffers를 사용하여 읽습니다.
    large_client_header_buffers 4 64k;

    # nginx를 통해 업로드되는 파일 크기 설정
    client_max_body_size 8m;

    # 효율적인 파일 전송 모드 활성화, sendfile 명령은 nginx가 sendfile 함수를 호출하여 파일을 출력할지 여부를 지정합니다. 일반 애플리케이션에는 on으로 설정하고, 다운로드 등 디스크 IO 부하가 큰 애플리케이션에는 off로 설정하여 디스크와 네트워크 I/O 처리 속도를 균형 있게 조절하고 시스템 부하를 줄일 수 있습니다. 참고: 이미지가 정상적으로 표시되지 않으면 이를 off로 변경합니다.
    sendfile on;

    # 디렉토리 목록 접근 활성화, 다운로드 서버에 적합하며 기본적으로 비활성화됩니다.
    autoindex on;

    # 이 옵션은 socket의 TCP_CORK 옵션 사용을 허용하거나 금지합니다. 이 옵션은 sendfile 사용 시에만 유효합니다.
    tcp_nopush on;
    tcp_nodelay on;

    # 장기 연결 타임아웃 시간, 단위는 초
    keepalive_timeout 120;

    # FastCGI 관련 매개변수는 웹사이트 성능을 개선하기 위해 설정됩니다: 리소스 사용 감소, 접속 속도 향상. 아래 매개변수는 이름만 봐도 이해할 수 있습니다.
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;

    # gzip 모듈 설정
    gzip on;  # gzip 압축 출력 활성화
    gzip_min_length 1k;  # 최소 압축 파일 크기
    gzip_buffers 4 16k;  # 압축 버퍼
    gzip_http_version 1.0;  # 압축 버전(기본값 1.1, 프론트엔드가 squid2.5이면 1.0 사용)
    gzip_comp_level 2;  # 압축 레벨
    gzip_types text/plain application/x-javascript text/css application/xml;  # 압축 유형
    gzip_vary on;

    # IP 연결 수 제한 활성화 시 필요
    limit_zone crawler $binary_remote_addr 10m;

    # 로드 밸런싱 설정
    backend_server {
        # upstream의 로드 밸런싱, weight는 가중치이며, 기기 구성에 따라 가중치를 정의할 수 있습니다. weight는 접속 비율에 비례합니다.
        server 192.168.80.121:80 weight=3;
        server 192.168.80.122:80 weight=2;
        server 192.168.80.123:80 weight=3;

        # nginx의 upstream은 현재 4가지 할당 방식을 지원합니다.
        # 1. 라운드 로빈(기본)
        # 각 요청이 순서대로 다른 백엔드 서버로 할당되며, 백엔드 서버가 다운되면 자동으로 제외됩니다.
        # 2. weight
        # 라운드 로빈 확률을 지정하며, weight는 접속 비율에 비례합니다. 백엔드 서버 성능이 다를 때 사용합니다.
        # 3. ip_hash
        # 각 요청이 접속 IP의 해시 결과에 따라 할당되므로 각 방문자가 특정 백엔드 서버에 고정되어 접속하게 되어 세션 문제를 해결할 수 있습니다.
        # 4. fair(제3자)
        # 백엔드 서버의 응답 시간에 따라 요청을 할당하며, 응답 시간이 짧은 서버가 우선적으로 할당됩니다.
    }

    # 가상 호스트 설정
    server {
        listen 80;
        server_name example.com www.example.com;
        index index.html index.htm index.php;
        root /var/www/example;

        # PHP 파일 처리
        location ~ .*.(php|php5)?$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi.conf;
        }

        # 이미지 캐시 시간 설정
        location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
            expires 10d;
        }

        # JS 및 CSS 캐시 시간 설정
        location ~ .*.(js|css)?$ {
            expires 1h;
        }

        # 로그 형식 설정
        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" $http_x_forwarded_for';

        # 이 가상 호스트의 접속 로그 정의
        access_log /var/log/nginx/example.access.log main;
    }
}

Nginx Location 구문 상세 설명

Location 구문 우선순위:

매칭 기호 매칭 규칙 우선순위
= 정확한 매칭 1
^~ 특정 문자열로 시작 2
~ 대소문자 구분 정규식 매칭 3
~* 대소문자 구분 안하는 정규식 매칭 4
!~ 대소문자 구분 정규식 매칭(불일치) 5
!~* 대소문자 구분 안하는 정규식 매칭(불일치) 6
/ 일반 매칭, 모든 요청에 매칭 7

Nginx와 UWSGI 연동

UWSGI는 Python 애플리케이션을 실행하기 위한 웹 서버 인터페이스이며, Nginx와 함께 사용되어 웹 서비스를 제공합니다.

UWSGI 설정 예시

[uwsgi]
# 프로젝트 디렉토리
chdir = /path/to/your/project
# WSGI 모듈
module = yourproject.wsgi:application
# 프로세스 및 스레드 수
processes = 4
threads = 2
# 소켓 설정
socket = /tmp/uwsgi.sock
# 소켓 권한
chmod-socket = 664
# 마스터 프로세스 활성화
master = true
# 데몬 모드
daemonize = /var/log/uwsgi.log
# 자동 재시작 설정
py-autoreload = 1
# 최대 요청 수 후 재시작
max-requests = 5000
# 종료 시 환경 정리
vacuum = true

Nginx에서 UWSGI 연동 설정

server {
    listen 80;
    server_name yourdomain.com;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/uwsgi.sock;
        uwsgi_param Host $host;
        uwsgi_param X-Real-IP $remote_addr;
        uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # 정적 파일 처리
    location /static/ {
        alias /path/to/your/static/files/;
    }
}

Supervisor를 이용한 프로세스 관리

Supervisor는 Python 기반의 프로세스 관리 도구로, 백그라운드 작업을 자동으로 실행하고 관리합니다.

Supervisor 설치 및 설정

# 설치
pip install supervisor

# 설정 파일 생성
echo_supervisord_conf > /etc/supervisord.conf

# 프로세스 정의 추가
[program:yourapp]
command=/path/to/your/command
directory=/path/to/your/app
autostart=true
autorestart=true
stderr_logfile=/var/log/yourapp.err.log
stdout_logfile=/var/log/yourapp.out.log

# Supervisor 시작
supervisord -c /etc/supervisord.conf

# 프로세스 제어
supervisorctl start yourapp
supervisorctl stop yourapp
supervisorctl restart yourapp

Nginx + UWSGI + Supervisor 통합 아키텍처

이 아키텍처는 다음과 같은 흐름으로 작동합니다:

  1. Nginx가 클라이언트 요청을 수신합니다.
  2. 정적 파일 요청은 Nginx가 직접 처리합니다.
  3. 동적 요청은 UWSGI로 전달됩니다.
  4. UWSGI는 Python 애플리케이션을 실행하고 요청을 처리합니다.
  5. Supervisor는 UWSGI 프로세스를 관리합니다.

이 구성은 높은 성능, 안정성 및 확장성을 제공하며, 대규모 웹 애플리케이션 배포에 적합합니다.

태그: nginx uwsgi Supervisor 웹 서버 파이썬

5월 25일 14:32에 게시됨