NGINX 성능 튜닝 가이드 (NGINX Plus 포함)
지난 몇 년 동안, NGINX 성능 튜닝 이 주된 관심사였던 몇몇 파트너와 함께 작업해 왔습니다. 대화는 보통 우리가 발표한 성능 벤치마크와 일치시키기 어려운 상황에서 시작됩니다. 도전은 일반적으로 파트너가 기존의 SSL Key를 사용하거나 매우 큰 파일 페이로드를 대상으로 하는 등의 특정한 사용 사례로 바로 들어가서 NGINX Plus의 성능이 기대에 미치지 못하는 것으로 나타납니다.
어느 정도로는 예상되는 동작입니다. 항상 파트너에게 설명하는 내용은 소프트웨어 구성 요소로서, NGINX Plus는 가장 기본적인 HTTP 사용 사례를 다룰 때 사용할 수 있는 하드웨어에서 거의 line-rate 속도로 실행될 수 있다는 점입니다. 그러나 특정 사용 사례에서 우리가 발표한 숫자를 달성하기 위해서는, 종종 NGINX Plus의 구성 변경과 함께 저수준 OS 및 하드웨어 설정의 조정도 필요합니다.
지금까지의 모든 경우에서 우리의 파트너들은 고유한 사용 사례에 대해 매우 독특한 방식으로 OS 및 하드웨어 설정 구성에 집중함으로써 이론적인 성능 숫자를 달성할 수 있었습니다. 이러한 파트너들은 NGINX Plus가 이러한 구성 요소와 상호 작용하는 방식에 맞게 구성되어야 하는 것을 고려하여 사용 사례에 맞게 조정된 OS 및 하드웨어 설정 요소에 집중했습니다.
이 포스트는 성능에 영향을 줄 수 있는 구성 설정의 하위 집합에 대한 가이드일 뿐이며, 전체적인 목록은 아닙니다. 환경에 따라 아래에서 다루는 모든 설정을 변경하는 것이 반드시 적절한 것은 아닙니다.
목차
1. Workflow 조정
2. NGINX 구성 조정
2-1. SSL
2-2. 압축
2-3. 연결 처리
2-4. 로깅
2-5. 스레드 풀링 (thread pooling)
2-6. CPU Affinity
3. 사이징 권장 사항
3-1. CPU
3-2. RAM
3-3. Detail
3-4. 공유 메모리 영역
3-5. Disk I/O
1. NGINX 성능 튜닝 – Workflow 조정
성능 조정 문제를 해결할 때, 일반적으로 다음 작업 흐름을 권장합니다.
- 가능한 가장 일반적인 HTTP 사용 사례에서 NGINX Plus의 성능 테스트를 합니다. 이를 통해 특정 환경에 대한 올바른 벤치마킹 기준을 설정할 수 있습니다.
- 특정 사용 사례를 식별합니다. 예를 들어, 애플리케이션이 대용량 파일 업로드를 필요로 하는 경우나 높은 보안 수준을 요구하는 큰 SSL Key 크기를 다루는 경우 등, 최종 목표 사용 사례를 먼저 정의하세요.
- 사용 사례에 맞게 NGINX Plus를 구성하고 다시 테스트하여 환경의 이론적인 성능과 사용 사례의 실제 성능 사이의 델타를 결정합니다.
- 사용 사례에 가장 적합한 설정에 초점을 맞추어 한 번에 한 가지 설정을 조정하세요. 즉, 새로운 NGINX 지시문을 추가하는 동시에 많은 systemctl 설정을 변경하지 마세요. 작은 규모로 시작하고, 사용 사례에 가장 적합한 기능부터 시작하세요. 예를 들어, 보안이 중요한 환경에서는 먼저 SSL Key 유형과 크기를 변경하세요.
- 변경 사항이 성능에 영향을 미치지 않으면 설정을 기본값으로 되돌리세요. 각 개별 변경 사항을 진행함에 따라 관련 설정이 함께 성능에 영향을 미치는 경향이 보일 것입니다. 이는 필요에 따라 함께 조정할 수 있는 설정 그룹에 집중할 수 있도록 도와줍니다.
중요한 점은 각 배포 환경이 고유하며 네트워킹 및 애플리케이션 성능 요구 사항을 가지고 있다는 것입니다. 일부 값들을 운영 환경에서 변경하는 것이 권장되지 않을 수도 있습니다. 아래에 설명된 구성 조정의 결과는 애플리케이션 유형과 네트워킹 토폴로지에 따라 극적으로 다른 결과를 가져올 수 있습니다.
NGINX가 오픈 소스 커뮤니티에서 강력한 근간을 하고 있다는 점 때문에, 많은 사람들이 지난 몇 년 동안 성능 향상에 기여해왔습니다. 적용할 수 있는 경우, 제품 프로덕션 환경에서 이러한 솔루션을 이미 실전에서 테스트해 본 사람들로부터 특정 성능 조정 제안에 대한 외부 자료 링크를 포함하였습니다.
2. NGINX 성능 튜닝 – 구성 조정
NGINX 참조 문서에는 지원되는 값, 기본 설정 및 각 설정이 지원되는 범위에 대한 자세한 내용을 확인할 수 있습니다.
2-1. NGINX 성능 튜닝 – SSL
이 섹션에서는 느리고 불필요한 암호를 제거하는 방법에 대해 설명합니다.
SSL 성능이 중요한 경우, 환경에서 다른 Key 크기와 유형을 시도하여 특정 보안 요구 사항에 맞는 올바른 균형을 찾는 것이 좋습니다. 더 긴 Key를 사용하여 보안을 강화하거나 더 짧은 Key를 사용하여 성능을 높이는 것 사이에 특정 보안 요구사항에 맞는 올바른 균형을 찾을 수 있습니다. 간단한 테스트는 더 전통적인 RSA 에서 타원 곡선 암호화 (ECC) 로 전환하는 것입니다. ECC는 더 작은 Key 크기를 사용하므로 동일한 수준의 보안에 대해 계산 속도가 빠릅니다.
테스트를 위해 빠른 자체 서명 ECC P-256 Key를 생성하려면 다음 명령을 실행합니다.
# openssl ecparam -out ./nginx-ecc-p256.key -name prime256v1 -genkey
# openssl req -new -key ./nginx-ecc-p256.key -out ./nginx-ecc-p256-csr.pem -subj '/CN=localhost'
# openssl req -x509 -nodes -days 30 -key ./nginx-ecc-p256.key -in ./nginx-ecc-p256-csr.pem -out ./nginx-ecc-p256.pem
2-2. NGINX 성능 튜닝 – 압축
Gzip 매개변수는 NGINX가 콘텐츠를 전달하는 방식에 대한 세밀한 제어를 제공하기 때문에 잘못 설정하면 NGINX의 성능이 저하될 수 있습니다. gzip을 활성화하면 대역폭을 절약하고 느린 연결에서 페이지 로드 시간을 개선할 수 있습니다. (로컬 또는 합성 벤치마크에서 gzip을 활성화하더라도 실제 세계에서와 같은 이점이 나타나지 않을 수 있습니다.) 최적의 성능을 위해 다음과 같은 설정을 시도해보세요:
- 텍스트, JavaScript 및 CSS 파일과 같은 콘텐츠 gzip을 활성화합니다.
- 쓸데없이 압축 수준을 높이지 마세요. 이는 처리량에 상응하는 성능 향상 없이 CPU 작업이 증가합니다.
- 압축을 활성화 및 비활성화하여 다른 유형과 크기의 콘텐츠에 대한 압축 활성화의 효과를 평가하세요.
세분화된 gzip 제어에 대한 자세한 내용은 NGINX gzip 모듈에 대한 참조 문서에서 찾을 수 있습니다.
2-3. 연결 처리
연결 처리와 관련된 여러 튜닝 옵션이 있습니다. 적절한 구문, 적용 가능한 구성 블록(http, server, location) 등에 대한 자세한 내용은 링크된 참조 문서를 참조하십시오.
- accept-mutex off – 모든 worker process가 새로운 연결에 대해 알림을 받습니다. (NGINX 1.11.3 이후 및 NGINX Plus R10 이후의 기본 설정). 이 옵션을 사용하면 worker process가 순서대로 새로운 연결을 수락합니다.
애플리케이션 성능과 다양한 조건에서 테스트할 기회를 가지고 있는 경우를 제외하고는 기본값(off)을 유지하는 것을 권장합니다. 그러나 새로운 연결의 양이 적다면 시스템 리소스의 비효율적인 사용으로 이어질 수 있습니다. 일부 고부하 상황에서는 값을 on으로 변경하는 것이 도움이 될 수 있습니다.
- keepalive 128 – NGINX Plus에서 업스트림 서버로의 keepalive 연결을 활성화하며, 각 worker process의 캐시에 유지되는 최대 유휴 keepalive 연결 수를 정의합니다. 이 수를 초과하면 가장 최근에 사용되지 않은 연결이 닫힙니다. keepalive가 없으면 오버헤드가 더 많이 발생하며 연결 및 일시적인 포트가 효율적으로 사용되지 않습니다.
HTTP 트래픽의 경우, upstream 블록에 이 지시문을 포함하면 해당 upstream 그룹으로 트래픽을 프록시하는 모든 location 블록에 다음 지시문도 포함해야 합니다. 이 지시문은 개별 location 블록, 상위 server 블록 또는 http 레벨에 배치할 수 있습니다.- proxy_http_version 1.1 – NGINX Plus는 프록시 요청에 HTTP/1.1을 사용합니다.
- proxy_set_header Connection “” – NGINX Plus는 프록시 요청에서 연결 헤더를 제거합니다.
- multi_accept off – worker process는 한 번에 하나의 새로운 연결을 수락합니다(기본값). 이 옵션을 사용하면 worker process는 한 번에 모든 새로운 연결을 수락합니다.
변경할 이점이 있는지 확신이 서지 않는 한 기본값(해제)을 유지하는 것이 좋습니다. 예측 가능한 규모를 더 잘 측정하려면 기본값으로 성능 테스트를 시작하십시오. - proxy_buffering on – NGINX Plus는 가능한 한 빨리 프록시 서버로부터 응답을 받고 버퍼링합니다.(기본값). 비활성화된 경우 NGINX Plus는 응답을 받는 즉시 동기식으로 클라이언트에 전달하므로 NGINX Plus의 부하가 증가합니다.
응답 버퍼링을 비활성화하는 데이터 스트림에 즉시 액세스해야 하는 애플리케이션에만 필요합니다. - listen 80 reuseport – 포트 샤딩을 활성화합니다. 즉, 각 worker process에 대해 개별 수신 소켓이 생서되며 (SO_REUSEPORT 소켓 옵션을 사용), 커널이 들어오는 연결을 worker process 간에 분배를 할 수 있도록 합니다.
2-4. 로깅
로그는 시스템 관리 및 감사에 중요한 도구입니다. 그러나 대량의 데이터를 기록하고 대용량 로그를 저장하는 것은 시스템 리소스를 과도하게 사용할 수 있습니다. 그러나 성능 문제 해결을 위해 아주 특정한 경우나 목적에 따라 로깅을 비활성화하는 것을 권장합니다.
- access_log off – access logging을 비활성화 합니다.
- access_log /path/to/access.log main buffer=16k – 버퍼링을 활성화하여 로그에 액세스합니다.
많은 오픈 소스 프로젝트와 상용 업체에서 제공하는 syslog 프로토콜을 기반으로 한 중화된 로깅 시스템을 활용하면 이점을 얻을 수 있습니다. NGINX 및 NGINX Plus 서버에 대한 지표(로그에 기록된 정보를 집계한 것)가 필요한 경우, NGINX Amplify를 사용할 수 있습니다.
2-5. 스레드 풀링 (thread pooling)
스레드 풀링(thread pooling)은 작업 큐와 큐를 처리하는 여러 개의 스레드로 구성됩니다. worker process가 잠재적으로 긴 작업을 수행해야 할 때, 작업을 직접 처리하는 대신 작업을 풀의 큐에 넣고 어떤 빈 스레드에서든 가져와 처리할 수 있습니다.
스레드 풀링을 활성화하려면 aio thread 지시문을 포함합니다. 스레드 풀이 관리되는 방식은 다른 버퍼 관련 설정에 의해 영향을 받을 수 있습니다.
2-6. CPU Affinity
CPU affinity는 개별 worker process에 대해 NGINX Plus가 사용하는 CPU를 제어하는 데 사용되는 기술입니다. 이를 통해 worker process를 특정 CPU 코어에 바인딩하여 CPU 리소스를 효율적으로 활용할 수 있습니다. worker_cpu_affinity 지시문에 대한 자세한 정보 및 사용 방법은 참조 문서를 참고하십시오.
대부분의 경우, 우리는 기본값인 auto 매개변수 worker process 지시문을 권장합니다. 이는 사용 가능한 CPU 코어 수와 동일한 수의 worker process를 설정합니다.
그러나 NGINX Plus가 Docker와 같은 컨테이너 환경에서 실행될 때, 시스템 관리자는 호스트 머신에서 사용 가능한 코어보다 적은 코어를 컨테이너에 할당할 수 있습니다. 이 경우, NGINX Plus는 호스트에서 사용 가능한 코어 수를 감지하고, 해당 컨테이너 내에서 실제로 사용 가능한 코어 사이에서 worker를 회전시킵니다. 이 경우, worker_processes를 컨테이너에서 사용 가능한 코어 수로 설정하여 worker 수를 줄일 수 있습니다.
CPU Affinity 테스트
NGINX Plus를 사용하기 전에는 항상 실제 운영 환경과 유사한 트래픽을 이용하여 로드를 테스트하는 것이 좋습니다. 그러나 기본적인 테스트를 위해서는 wrk와 같은 로드 생성기를 사용할 수 있습니다. 이에 대한 자세한 설명은 여기에서 확인할 수 있습니다.
빠른 작업 세션으로 NGINX Plus를 로드합니다.
# wrk -t 1 -c 50 -d 20s http://localhost/1k.bin
필요한 경우 다음을 사용하여 테스트를 위한 간단한 1k.bin 파일을 만들 수 있습니다.
# dd if=/dev/zero of=1kb.bin bs=1024 count=1
CPU 보기 모드에서 top을 실행합니다(top이 시작된 후 1을 누름).
다양한 수의 프로세스 수와 어떤 CPU에 바인딩할 것인지를 변경하여 테스트를 반복하면 선형적인 스케일을 확인할 수 있습니다. 이는 사용 가능한 코어 중 적절한 하위 집합에 대한 액세스 제한을 설정하는 효과적인 방법입니다.
3. NGINX 성능 튜닝 – 사이징 권장 사항
다음은 일반 웹 서비스 및 로드 밸런싱에 대한 대략적인 사이징 추정입니다. 이 값들은 VOD 스트리밍이나 CDN에는 적합하지 않을 수 있습니다.
3-1. CPU
암호화되지 않은 트래픽의 1-2Gbps당 1개의 CPU 코어를 할당합니다.
작은(1-2KB) 응답 및 연결당 1개의 응답은 CPU 부하를 증가시킵니다.
3-2. RAM
OS 및 기타 일반 요구 사항에 1GB를 할당합니다.
나머지는 NGINX Plus 버퍼, 소켓 버퍼 및 가상 메모리 캐시로 나뉘며 연결당 대략적인 추정치는 1MB입니다.
3-3. Detail
- proxy_buffers(연결당) 디스크 I/O를 방지하려면 proxy_buffers 크기를 선택해야 합니다.
- 응답 크기가(proxy_buffers 크기 + proxy_buffer_size)보다 크면 응답이 디스크에 기록되어 I/O, 응답 시간 등이 증가할 수 있습니다.
3-4. 공유 메모리 영역
표면적으로 영역은 상태, 메트릭, 쿠키, 상태 확인 등과 같은 여러 업스트림 서버에서 공유하는 데이터를 저장하는 데 사용됩니다.
그러나 영역은 NGINX Plus가 worker process 등 다양한 구성 요소 간의 부하 분산을 어떻게 처리하는지에도 영향을 미칠 수 있습니다. 영역이 저장하는 구성 요소와 영향에 대한 자세한 설명은 NGINX Plus 관리 가이드를 참조하십시오.
정확한 설정을 규정하는 것은 불가능합니다. 사용 패턴은 매우 다양하기 때문입니다. sticky 지시문을 사용한 세션 지속성, health check, DNS re-resolving과 같은 각 기능은 영역의 크기에 영향을 줍니다. 예를 들어, sticky route 세션 지속성 방법과 하나의 헬스 체크를 사용하는 경우, 256KB의 영역은 지정된 업스트림 서버의 정보를 수용할 수 있습니다.
- 128 servers (각각 IP 주소:포트 쌍으로 정의됨)
- 88 servers (각각은 호스트명이 단일 IP 주소로 확인되는 호스트명:포트 쌍으로 정의됨)
- 12 servers (각각 호스트명이 여러 IP 주소로 확인되는 호스트명:포트 쌍으로 정의됨)
영역을 생성할 때 공유 메모리 영역이 영역 이름으로 제어된다는 점에 유의해야 합니다. 모든 영역에 동일한 이름을 사용하면 모든 업스트림의 데이터가 해당 영역에 저장됩니다. 이 경우 크기를 초과할 수 있습니다.
3-5. Disk I/O
디스크 I/O의 제한 요소는 초당 I/O 작업 수(iops)입니다.
NGINX Plus는 로깅 및 캐싱을 포함한 여러 기능을 위해 디스크 I/O 및 iops에 의존합니다.
사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.