Nginx 성능 최적화: 더 빠른 웹사이트를 위한 팁

포괄적인 성능 최적화 가이드를 통해 Nginx 서버의 잠재력을 최대한 발휘하십시오. 워커 프로세스 미세 조정, 강력한 캐싱 전략 구현, 효율적인 압축(Gzip/Brotli) 활성화, 연결 처리 최적화 방법을 배우세요. 이 문서는 로드 시간을 획기적으로 줄이고 사용자 경험을 개선하며 웹사이트의 전반적인 속도와 효율성을 높이는 실용적인 Nginx 구성 팁과 모범 사례를 제공합니다. 최고의 성능을 추구하는 시스템 관리자와 웹 개발자에게 필수적인 필독서입니다.

Nginx 성능 최적화: 더 빠른 웹사이트를 위한 팁

느린 사이트는 일반적으로 몇 가지 원인에서 비롯됩니다: 비싼 업스트림 응답, 누락된 캐시 헤더, 과도하게 큰 자산, 차단된 워커, 또는 트래픽 대신 기본값에 맞춰 조정된 서버입니다. Nginx 성능 최적화는 먼저 측정하고, 한 번에 하나의 설정만 변경하며, 구성을 읽기 쉽게 유지할 때 가장 효과적입니다.

아래 예제를 시작점으로 사용한 다음 자체 앱에 대해 부하 테스트를 수행하세요. 정적 파일 서버, WordPress/PHP-FPM 사이트, API 리버스 프록시는 서로 다른 트레이드오프가 필요합니다.

Nginx 성능 병목 현상 이해

병목 현상을 찾는 것부터 시작하세요. 일반적인 원인은 다음과 같습니다:

  • CPU 사용량: CPU 부하가 높으면 요청 처리, 압축 및 TLS 작업이 느려집니다.
  • 메모리 압력: 스와핑은 지연 시간에 심각한 영향을 미칩니다.
  • 네트워크 I/O: 느린 링크, 작은 업스트림 윈도우 또는 패킷 손실이 응답 시간을 지배할 수 있습니다.
  • 디스크 I/O: 정적 파일, 캐시 파일 및 로그는 여전히 스토리지에 접근합니다.
  • 업스트림 지연 시간: Nginx는 빠를 수 있지만 앱 서버가 느릴 수 있습니다.

top, htop, iostat, ss, 액세스 로그 및 Nginx의 stub_status 모듈과 같은 도구를 사용하여 무엇을 조정할지 결정하는 데 도움을 받을 수 있습니다.

핵심 Nginx 최적화 기술

워커 프로세스 및 연결

worker_processes 지시문은 Nginx가 시작하는 워커 프로세스 수를 제어합니다. auto는 Nginx가 사용 가능한 CPU 코어를 감지하므로 실용적인 기본값입니다.

# worker_processes를 CPU 코어 수로 설정
worker_processes auto;

각 워커 프로세스 내에서 worker_connections은 해당 워커가 열 수 있는 동시 연결 수를 제한합니다. 대략적인 상한은 worker_processes * worker_connections이지만 실제 용량은 업스트림 연결, 열린 파일 제한, keep-alive 동작 및 운영 체제 제한에 따라 달라집니다.

# 트래픽이 많은 사이트의 경우 worker_connections 증가
worker_connections 1024;

Too many open files 오류가 표시되면 worker_connections만 높이는 것으로는 충분하지 않습니다. 서비스의 파일 디스크립터 제한(종종 systemd LimitNOFILE 또는 셸 제한으로 제어됨)도 확인하세요.

캐싱 전략

캐싱은 일반적으로 가장 영향력이 큰 Nginx 성능 최적화입니다. 반복 작업을 방지하기 때문입니다.

브라우저 캐싱

브라우저에 이미지, CSS 및 JavaScript와 같은 버전이 지정된 정적 자산을 캐시하도록 지시합니다. app.8f3c1.css와 같이 배포 시 파일 이름이 변경되는 경우에만 긴 수명을 사용하세요.

location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public";
}

프록시 캐싱

Nginx가 리버스 프록시인 경우 선택한 백엔드 응답을 캐시할 수 있습니다. 이는 공개 페이지, 명확한 신선도 규칙이 있는 API 응답 및 사용자별로 변하지 않는 비용이 많이 드는 페이지에 효과적입니다.

먼저 http 블록에 캐시 영역을 정의합니다:

http {
    # ... 다른 http 구성 ...
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
    # ...
}
  • /var/cache/nginx: 캐시 파일이 저장될 디렉토리입니다.
  • levels=1:2: 캐시의 디렉토리 구조를 정의합니다.
  • keys_zone=my_cache:10m: 캐시 키를 저장하기 위해 10MB 크기의 my_cache라는 공유 메모리 영역을 생성합니다.
  • max_size=1g: 캐시의 최대 크기를 설정합니다.
  • inactive=60m: 60분 동안 액세스되지 않은 캐시 항목을 제거합니다.

그런 다음 location 블록에서 캐싱을 활성화합니다:

location / {
    proxy_pass http://your_backend_app;
    proxy_cache my_cache;
    proxy_cache_valid 200 302 10m; # 200 및 302 응답을 10분 동안 캐시
    proxy_cache_valid 404 1m;     # 404 응답을 1분 동안 캐시
    add_header X-Cache-Status $upstream_cache_status;
}

add_header X-Cache-Status $upstream_cache_status;는 디버깅에 유용하며 요청이 캐시 적중, 누락 또는 우회되었는지 여부를 보여줍니다.

캐시 키가 응답을 변경하는 데이터를 설명하지 않는 한 개인화된 페이지를 캐시하지 마십시오. 예를 들어 로그인된 대시보드는 일반적으로 프록시 캐시를 우회해야 하지만 /assets/logo.png는 오랫동안 캐시될 수 있습니다.

압축

압축은 HTML, CSS, JavaScript, JSON 및 XML과 같은 텍스트 기반 응답의 전송 크기를 줄입니다. JPEG, PNG, MP4 또는 많은 아카이브 형식과 같이 이미 압축된 파일에는 거의 도움이 되지 않습니다.

http {
    # ...
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    # ...
}
  • gzip on;: Gzip 압축을 활성화합니다.
  • gzip_vary on;: Vary: Accept-Encoding 헤더를 추가합니다. 이는 캐싱 프록시에 중요합니다.
  • gzip_proxied any;: 프록시된 요청에 대한 응답도 압축합니다.
  • gzip_comp_level 6;: 압축 수준을 설정합니다(1-9, 높을수록 압축률은 좋지만 CPU 사용량이 증가).
  • gzip_types ...;: 압축할 MIME 유형을 지정합니다.

Brotli는 텍스트 자산을 잘 압축할 수 있지만 표준 오픈 소스 Nginx 빌드에 모두 Brotli 지원이 포함되어 있지는 않습니다. Brotli 지시문을 추가하기 전에 패키지 또는 모듈 세트를 확인하세요.

연결 처리 및 Keep-Alive

keepalive_timeout 지시문은 유휴 클라이언트 연결이 열려 있는 시간을 제어합니다. 연결을 재사용하면 추가 TCP 및 TLS 핸드셰이크를 피할 수 있지만 유휴 연결은 여전히 리소스를 소비합니다.

http {
    # ...
    keepalive_timeout 65;
    keepalive_requests 1000;
    # ...
}
  • keepalive_timeout 65;: keep-alive 제한 시간을 65초로 설정합니다.
  • keepalive_requests 1000;: 단일 keep-alive 연결을 통해 수행할 수 있는 최대 요청 수를 설정합니다.

짧은 요청이 많은 API의 경우 keep-alive가 도움이 됩니다. 유휴 클라이언트가 많은 소규모 서버의 경우 더 짧은 제한 시간이 더 나을 수 있습니다.

버퍼링 및 요청 크기 제한

Nginx는 클라이언트 본문 및 프록시된 응답에 버퍼를 사용합니다. 기본값은 많은 사이트에 적합하지만 업로드가 많은 앱과 대용량 업스트림 헤더에는 명시적인 설정이 필요할 수 있습니다.

http {
    # ...
    client_body_buffer_size 10K;
    client_max_body_size 8M;
    proxy_buffers 8 16k;
    proxy_buffer_size 16k;
    proxy_connect_timeout 60;
    proxy_send_timeout 60;
    proxy_read_timeout 60;
    # ...
}
  • client_body_buffer_size: 클라이언트 요청 본문을 읽는 데 사용되는 버퍼 크기입니다.
  • client_max_body_size: 클라이언트 요청 본문의 최대 허용 크기입니다.
  • proxy_buffers, proxy_buffer_size: Nginx가 프록시 역할을 할 때 버퍼링을 제어합니다.

버퍼 설정을 무분별하게 복사하지 마십시오. upstream sent too big header 오류가 표시되면 proxy_buffer_size를 높이기 전에 업스트림 헤더를 조사하십시오. 업로드가 413 Request Entity Too Large 오류와 함께 실패하면 client_max_body_size를 앱이 실제로 지원하는 크기로 설정하십시오.

TLS 최적화

HTTPS 사이트의 경우 TLS 설정은 지연 시간과 보안 모두에 영향을 미칩니다.

  • 세션 재개: 세션 캐시를 사용하여 반복 연결 속도를 높입니다.
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    
  • TLS 버전: 호환성 요구 사항에 달리 명시되지 않는 한 TLS 1.2 및 TLS 1.3을 활성화합니다.
  • OCSP 스테이플링: 인증서 체인이 지원하는 경우 인증서 확인 왕복 시간을 줄일 수 있습니다.
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    

정적 파일 제공

Nginx는 정적 파일 제공에 강력합니다. 이러한 지시문은 http 블록에서 일반적입니다:

  • sendfile: 지원되는 시스템에서 커널이 파일 데이터를 소켓에 직접 복사하도록 합니다.
    sendfile on;
    
  • tcp_nopushtcp_nodelay: 일반적인 HTTP 워크로드에 대한 패킷 전송 동작을 조정합니다.
    tcp_nopush on;
    tcp_nodelay on;
    

모니터링 및 테스트

각 변경 후에는 테스트하고 비교하십시오. 유용한 도구는 다음과 같습니다:

  • Nginx stub_status: 활성 연결, 수락된 연결, 처리된 연결 및 요청.
  • top/htop: CPU 및 메모리 압력.
  • iostat: 디스크 I/O.
  • WebPageTest 또는 PageSpeed Insights: 브라우저 측 성능.
  • wrk, ab 또는 hey: 제어된 엔드포인트에 대한 로컬 부하 테스트.

이전 구성의 복사본을 보관하고 sudo nginx -t를 실행한 후 다시 로드하고 지연 시간, 오류율, CPU 및 업스트림 응답 시간을 비교하십시오. 가장 좋은 Nginx 성능 최적화는 측정으로 증명할 수 있는 최적화입니다.

실용적인 결론

측정부터 시작한 다음 가장 큰 병목 현상을 먼저 수정하십시오. 대부분의 웹사이트에서 이는 적절한 워커 제한 설정, 정적 자산에 대한 브라우저 캐싱 추가, gzip 활성화, 안전한 업스트림 응답 캐싱 및 다시 로드할 때마다 로그를 확인하는 것을 의미합니다.