블로그 | NGINX

커널 TLS 및 SSL_sendfile( )을 사용하여 NGINX 성능 개선

NGINX-F5-수평-검정-유형-RGB의 일부
미하일 이사첸코프 썸네일
미하일 이사첸코프
2021년 11월 11일 게시

TLS(전송 계층 보안)는 매우 인기 있는 암호화 프로토콜입니다. 커널에 TLS를 구현하면(kTLS) 사용자 공간과 커널 간의 작업 복사 필요성이 크게 줄어들어 성능이 향상됩니다.

kTLS와 sendfile()을 결합하면 데이터가 네트워크 스택으로 전달되기 전에 커널 공간에서 직접 암호화됩니다. 이를 통해 TLS 라이브러리로 암호화된 데이터를 사용자 공간에 복사한 다음 다시 커널 공간으로 복사하여 전송할 필요가 없습니다. kTLS는 또한 TLS 처리를 하드웨어로 오프로드할 수 있게 하며, 여기에는 TLS 대칭 암호화 처리를 네트워크 장치로 오프로드하는 것도 포함됩니다.

최신 Linux와 FreeBSD 커널은 TLS를 커널로 오프로드하는 것을 지원하며, 이제 NGINX 오픈 소스도 이 기능을 지원합니다! NGINX 1.21.4에서는 SSL_sendfile() 을 사용하여 정적 파일과 캐시된 응답을 제공할 때 kTLS를 지원하여 성능을 크게 향상시킬 수 있습니다. 아래에 자세히 설명된 대로, NGINX가 SSL_sendfile()을 사용하려면 커널과 OpenSSL 모두 kTLS로 빌드되어야 합니다.

이 블로그에서는 kTLS를 지원하는 운영체제와 OpenSSL 버전을 자세히 설명하고, kTLS를 위한 커널과 NGINX를 빌드하고 구성하는 방법을 보여줍니다. kTLS에서 기대할 수 있는 성능 향상을 알려드리기 위해 FreeBSD와 Ubuntu에서 실시한 테스트의 사양과 결과도 공유하겠습니다.

참고: kTLS 구현은 매우 새롭고 빠르게 발전하고 있습니다. 이 블로그에서는 2021년 11월 기준 kTLS 지원에 대해 설명하고 있지만, 여기에 제공된 정보와 지침의 변경 사항에 대한 nginx.org 와 NGINX 블로그<.htmla>의 공지 사항을 주시하세요.

일반 요구 사항

  • 운영 체제 - 다음 중 하나:

    • FreeBSD 13.0+. 2021년 11월 현재 FreeBSD 13.0+은 OpenSSL 3.0.0+을 통합하기 위한 NGINX 수동 빌드 없이 NGINX에서 kTLS를 지원하는 유일한 OS입니다. FreeBSD에서 kTLS로 NGINX 활성화를 참조하세요.

    • Linux 커널 버전 4.17 이상을 기반으로 구축된 Linux 배포판. 가능하면 버전 5.2 이상을 기반으로 구축된 배포판을 사용하는 것이 좋습니다. (kTLS 지원은 실제로 버전 4.13에서 제공되지만 OpenSSL 3.0.0에는 커널 헤더 버전 4.17 이상이 필요합니다.)

  • OpenSSL – 버전 3.0.0 이상

  • NGINX – 버전 1.21.4 이상(메인라인)

    [ 편집기NGINX Plus R27 이상은 적격 Linux 기반 운영 체제 버전에서 kTLS를 지원하고, NGINX Plus R26 이상은 적격 FreeBSD 버전에서 kTLS를 지원합니다. 지원되는 OS에 대한 자세한 내용은 NGINX Plus 릴리스 페이지를 참조하세요.]

운영 체제 지원

kTLS를 지원하는 OS

2021년 11월 현재 NGINX 오픈 소스가 지원하는 OS 중 kTLS와 해당 암호를 지원하는 OS는 다음과 같습니다. 암호화 지원에 대한 자세한 내용은 TLS 프로토콜 및 암호화 지원을 참조하세요.

  TLSv1.2 암호 TLSv1.3
암호 모음
TLS_CHACHA20_POLY1305_SHA256 암호 리눅스 커널 버전
아마존 리눅스 2 * 5.10
센트OS 8 ** 4.18
프리BSD 13.x *** 없음
RHEL 8 4.18
SLES 15 SP2 5.3
우분투 20.04 ❌​​ 5.4
우분투 21.04 5.11
우분투 21.10 5.13

  * 커널 버전은 4.14가 아닌 5.10이어야 합니다. kTLS를 지원하지 않는 OSAmazon Linux 2 FAQ를 참조하세요.
** RHEL 8의 업스트림 소스로서 kTLS 지원 상태를 상속합니다.
*** FreeBSD 커밋 로그를 참조하세요

kTLS를 지원하지 않는 OS

다음 OS는 표시된 이유로 kTLS를 지원하지 않습니다.

  • Alpine Linux 3.11–3.14 – 커널은 CONFIG_TLS=n 옵션으로 빌드되었으며, 이는 kTLS를 모듈이나 커널의 일부로 빌드하는 것을 비활성화합니다.
  • Amazon Linux 2 – 기본 Amazon Linux 2 AMI의 경우 Linux 커널 버전은 4.14입니다( Amazon Linux 2 FAQ 참조).
  • CentOS 7.4+ – Linux 커널 버전은 3.10입니다. RHEL 7.4+의 업스트림 소스로부터 kTLS 지원 상태를 상속받습니다.
  • Debian 10 및 11 – 커널은 CONFIG_TLS=n 옵션으로 빌드되었습니다( Debian 버그 보고 로그 참조).
  • RHEL 7.4+ – Linux 커널 버전은3.10 .
  • SLES 12 SP5+ – Linux 커널 버전은4.12 .
  • Ubuntu 18.04 LTS – Linux 커널 버전은4.15 .

TLS 프로토콜 및 암호 지원

위에서 자세히 설명한 대로, kTLS를 지원하는 OS는 TLS 프로토콜과 암호에 대한 지원이 다릅니다.

TLSv1.2를 사용하면 kTLS 모듈이 다음 암호를 지원합니다.

  • AES128-GCM-SHA256
  • AES256-GCM-SHA384
  • ECDHE-RSA-AES128-GCM-SHA256
  • ECDHE-RSA-AES256-GCM-SHA384

TLSv1.3을 사용하면 kTLS 모듈이 다음 암호화 제품군을 지원합니다.

  • TLS_AES_128_GCM_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHACHA20_POLY1305_SHA256 ( kTLS를 지원하는 OS 에 지정된 일부 OS만 해당)

NGINX 바이너리에서 OpenSSL이 지원하는 TLS 암호 중 어떤 것이 활성화되어 있는지 확인하려면 NGINX를 빌드한 디렉토리(예: 홈 디렉토리)에서 openssl-3.0.0/.openssl/bin/openssl ciphers 명령을 실행합니다.

NGINX에서 kTLS 활성화

소개에서 언급했듯이 kTLS는 모든 암호화 및 복호화가 커널에서 이루어지기 때문에 NGINX 성능을 향상시킵니다. 데이터는 네트워크 스택으로 전달되기 전에 커널 공간에서 직접 암호화되므로 TLS 라이브러리에서 암호화하기 위해 데이터를 사용자 공간에 복사한 다음 다시 커널 공간으로 복사하여 전송할 필요가 없습니다.

NGINX를 사용한 커널 TLS(kTLS) 다이어그램

커널에 kTLS 로딩

최신 FreeBSD 및 Linux 배포판에서는 kTLS가 일반적으로 모듈로 빌드됩니다( CONFIG_TLS=m 옵션 사용). NGINX를 시작하기 전에 kTLS 모듈을 커널에 명시적으로 로드해야 합니다.

  • FreeBSD에서는 루트 사용자로 다음 명령을 실행하세요.

    # kldload ktls_ocf.ko # sysctl kern.ipc.tls.enable=1
    

    FreeBSD 명령 옵션에 대한 자세한 내용은 ktls(4) 의 man 페이지를 참조하십시오.

  • Linux 배포판에서는 루트 사용자로 이 명령을 실행합니다.

    # 모드프로브 TLS
    

FreeBSD에서 kTLS로 NGINX 활성화

FreeBSD의 NGINX에서 kTLS 지원을 활성화하려면 Linux 배포판과 동일한 지침을 사용하면 됩니다. 그러나 FreeBSD 포트 컬렉션security/openssl-devel 포트에서 kTLS를 탑재한 NGINX 빌드를 활용하려면 다음 단계를 수행하는 것이 좋습니다. kTLS에 대한 개요를 포함한 자세한 내용은 FreeBSD 웹사이트의 커널에서 TLS 오프로드를 참조하세요.

  1. 구성 메뉴에서 적절한 옵션을 선택하여 kTLS 지원으로 OpenSSL 3.0을 빌드합니다.

    # cd /usr/ports/security/openssl-devel && make config && make install
    
  2. openssl-devel을 기본 SSL 라이브러리로 사용하도록 /etc/make.conf를 수정합니다.

    # echo "기본 버전+=ssl=openssl-devel" >> /etc/make.conf
    
  3. NGINX 빌드:

    # cd /usr/ports/www/nginx-devel && make install
    

Linux 배포판에서 kTLS로 NGINX 빌드

대부분의 현재 Linux 배포판에는 OpenSSL 3.0.0 이전 버전(일반적으로 1.1 버전)이 포함되어 있습니다. 따라서 OpenSSL 3.0.0을 사용하여 소스에서 NGINX를 빌드해야 합니다.

kTLS 지원을 활성화하는 configure 명령의 두 가지 중요한 옵션은 다음과 같습니다.

  • --with-openssl=../openssl-3.0.0
  • --with-openssl-opt=ktls 사용 가능

다른 구성 옵션은 nginx.org 에서 제공하는 공식 NGINX 바이너리 패키지 에 포함된 모듈에 대한 것입니다. 대신 사용자 정의 모듈 세트를 지정할 수 있습니다. 현재 NGINX 바이너리에 사용된 빌드 옵션을 보려면 nginx -V를 실행하세요.

OpenSSL 3.0.0으로 NGINX를 빌드하려면 다음 명령을 실행하세요.

$ wget https://nginx.org/download/nginx-1.21.4.tar.gz $ wget https://www.openssl.org/source/openssl-3.0.0.tar.gz $ tar xzf openssl-3.0.0.tar.gz $ cd nginx-1.21.4 $ ./configure \ --with-debug \ --prefix=/usr/local \ --conf 경로=/usr/local/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx.pid \ --lock-path=/var/run/nginx.lock \ --http-클라이언트-바디-온도-경로=/var/캐시/nginx/클라이언트_온도 \ --http 프록시 임시 경로=/var/캐시/nginx/프록시_온도 \ --http-fastcgi 임시 경로=/var/캐시/nginx/fastcgi_temp \ --http-uwsgi 임시 경로=/var/캐시/nginx/uwsgi_temp \ --http-scgi 임시 경로=/var/캐시/nginx/scgi_temp \ --user=nginx \ --group=nginx \ --compat와 함께 \ --파일 aio와 함께 \ --스레드와 함께 \ --http_추가_모듈과 함께 \ --http_인증_요청_모듈과 함께 \ --http_dav_모듈과 함께 \ --http_flv_모듈과 함께 \ --http_gunzip_모듈과 함께 \ --http_gzip_정적_모듈과 함께 \ --http_mp4_모듈과 함께 \ --http_랜덤_인덱스_모듈과 함께 \ --with-http_realip_모듈 \ --with-http_보안_링크_모듈 \ --with-http_슬라이스_모듈 \ --with-http_ssl_모듈 \ --with-http_스텁_상태_모듈 \ --with-http_서브_모듈 \ --with-http_v2_모듈 \ --with-메일 \ --with-메일_ssl_모듈 \ --with-스트림 \ --with-스트림_realip_모듈 \ --with-스트림_ssl_모듈 \ --with-스트림_ssl_사전읽기_모듈 \ --with-openssl=../openssl-3.0.0 \ --with-openssl-opt=enable-ktls \ --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ -with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' $ make –j4 $ make install

메모: 결과적으로 생성된 NGINX 바이너리는 OpenSSL 3.0.0 라이브러리와 정적으로 연결됩니다. 나중에 OpenSSL을 패치해야 하는 경우 새로운 OpenSSL 소스 아카이브를 다운로드하여 압축을 푼 다음, 위의 명령을 실행하여 NGINX 바이너리를 다시 빌드해야 합니다.

NGINX 구성

kTLS를 활성화하려면 테스트 에 사용된 샘플 구성과 같이 server{} 컨텍스트에서 Options KTLS 매개변수와 함께 ssl_conf_command 지시문을 포함합니다.

worker_processes 자동;오류_로그 /var/log/nginx/error.log 디버그;

이벤트 {}

http {
sendfile 켜짐;

서버 {
수신 443 ssl;
ssl_certificate ssl/example.crt;
ssl_certificate_key ssl/example.key;
ssl_conf_command 옵션 KTLS;
ssl_protocols TLSv1.3;

위치 / {
루트 /데이터;
}
}
}

kTLS가 활성화되어 있는지 확인

NGINX가 kTLS를 사용하는지 확인하려면 디버깅 모드를 활성화 하고 오류 로그에서 BIO_get_ktls_send()SSL_sendfile() 을 확인하세요.

$ grep BIO /var/log/nginx/error.log 2021/11/10 16:02:46 [디버그] 274550#274550: *2 BIO_get_ktls_send(): 1 2021/11/10 16:02:49 [디버그] 274550#274550: *3 BIO_get_ktls_send(): 1 $ grep SSL_sendfile /var/log/nginx/error.log 2021/11/10 16:02:46 [디버그] 274550#274550: *2 SSL_sendfile: 1048576 2021/11/10 16:02:49 [디버그] 274550#274550: *3 SSL_sendfile: 1048576

메모: 특히 프로덕션 환경에서는 이러한 검사를 수행한 후에는 디버깅 모드를 비활성화하는 것이 좋습니다. 디버그 로깅은 쓰기 작업량이 많기 때문에 성능 저하를 초래합니다. 또한, 디버그 로그가 너무 커져서 디스크 파티션의 사용 가능한 공간을 빠르게 고갈시킬 수 있습니다.

kTLS를 통한 성능 개선

정적 파일과 캐시된 응답을 무거운 부하에서 제공할 때 SSL_sendfile()은 사용자 공간 TLS에 비해 처리량을 최대 2배까지 증가 시킬 수 있지만 성능 향상의 크기는 다양한 요인(디스크 성능, 시스템 부하 등)에 따라 크게 달라집니다. 네트워크 카드가 TLS 오프로드를 지원하는 경우 CPU 사용량을 줄이는 것도 가능합니다.

성능 테스트

설정에서 성능 향상을 측정하려면 다음 지침에 따라 간단한 단일 스레드 테스트를 실행하세요. 아래에 자세히 설명된 대로, 테스트 결과에 따르면 특별한 튜닝 없이도 성능이 최대 30% 가까이 향상되었습니다.

사용된 하드웨어 및 소프트웨어:

  • AWS t3.medium 인스턴스:
    • 4GB램
    • 20GB 일반용 SSD
    • 2개의 코어가 있는 Intel® Xeon® Platinum 8259CL CPU @ 2.50GHz
  • FreeBSD 13.0 및 Ubuntu 21.10
  • TLS_AES_256_GCM_SHA384 암호 제품군을 사용한 TLSv1.3
  • NGINX 1.21.4는 NGINX에서 kTLS 활성화 에 지정된 대로 빌드 및 구성되었습니다.

테스트를 수행하려면:

  1. 디스크 캐시에 완전히 들어갈 수 있는 큰 파일을 만듭니다.

    # 잘라내기 -s 1g /data/1G
    
  2. 처리량을 확인하려면 이 명령을 실행하세요. 더 정확한 결과를 얻으려면 기본 명령을 여러 번 반복합니다. 기본적인 통계 분석을 위해 출력을 ministat 유틸리티[ FreeBSD ][ Ubuntu ]로 파이프합니다.

     

    # i in 'seq 1 100'에 대해 curl -k -s -o /dev/null -w '%{speed_download}\n' https://localhost/1G | ministat를 실행합니다.
    

성능 테스트 결과

다음은 ministat 의 출력으로 표시된 테스트 결과이며, 각 값은 초당 킬로바이트 단위의 다운로드 속도를 나타냅니다. 가독성을 위해 출력은 두 줄로 나뉩니다.

kTLS 없이 FreeBSD 13.0의 처리량:

    N 최소 최대 중간값 ...x 10 532225 573348 555616 ... 

...      평균 표준 편차
... 555155.6 10239.137

kTLS를 사용한 FreeBSD 13.0의 처리량:

    N 최소 최대 중간값 ...x 10 629379 723164 717349 ... 

...      평균 표준 편차
... 708600.4 28304.766

kTLS가 없는 Ubuntu 21.10의 처리량:

    N 최소 최대 중간값 ...x 10 529199 705720 662354 ... 

...      평균 표준 편차
... 654321.6 48025.103

kTLS를 사용한 Ubuntu 21.10의 처리량:

    N 최소 최대 중간값 ...x 10 619105 760208 756278 ... 

...      평균 표준 편차
... 741848.3 43255.246

저희의 테스트에 따르면 kTLS는 Ubuntu보다 FreeBSD에서 성능을 더욱 향상시켰습니다. 개선율은 다음과 같습니다.

  최소 맥스 중앙값 평균
프리BSD 13.0 18% 26% 29% 28%
우분투 21.10 16% 8% 14% 13%

요약

NGINX 1.21.4에서는 SSL_sendfile()을 사용하여 정적 파일과 캐시된 응답을 제공할 때 kTLS에 대한 지원을 도입합니다. 당사 테스트 결과, 운영 체제에 따라 성능이 8~29% 향상되는 것으로 나타났습니다.

저희는 kTLS와 NGINX에 대한 여러분의 경험, 특히 다른 OS에서의 테스트 결과에 대해 듣고 싶습니다! 아래의 댓글란에 공유해 주시기 바랍니다.


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