kTLS(Kernel TLS) 및 SSL_sendfile( )로 NGINX 성능 향상
TLS(Transport Layer Security)는 매우 널리 사용되는 암호화 프로토콜입니다. 커널(kTLS)에서 TLS를 구현하면 User space과 커널 간의 복사 작업의 필요성이 크게 감소하여 성능이 향상됩니다.
kTLS 와 sendfile()을 결합하면 데이터가 전송을 위해 네트워크 스택으로 전달되기 전에 Kernel space에서 직접 암호화된다는 것을 의미합니다. 이렇게 하면 데이터를 TLS 라이브러리로 암호화하기 위해 User space으로 복사한 다음 전송을 위해 다시 Kernel space으로 복사할 필요가 없습니다. kTLS 는 또한 네트워크 장치에 대한 TLS 대칭 암호화 처리의 Offload를 포함하여 하드웨어에 대한 TLS 처리의 Offload를 가능하게 합니다.
최신 Linux 및 FreeBSD 커널은 TLS를 커널로 Offload 하는 것을 지원하며, NGINX Open Source도 지원합니다. NGINX는 SSL_sendfile()을 사용하여 정적 파일 및 캐시 된 응답을 제공할 때 kTLS를 지원하므로 성능이 크게 향상될 수 있습니다. 아래에 자세히 설명된 대로 NGINX가 SSL_sendfile()을 사용하려면 커널과 OpenSSL 모두 kTLS 로 Build 되어야 합니다.
이 포스트에서는 kTLS 를 지원하는 운영체제 및 OpenSSL 버전에 대해 자세히 설명하고 kTLS 용 커널 및 NGINX를 Build 하고 구성하는 방법을 보여줍니다. kTLS에서 기대할 수 있는 성능 향상에 대한 아이디어를 제공하기 위해 FreeBSD 및 Ubuntu에 대한 테스트 사양과 결과도 공유합니다.
목차
1. 일반 요구 사항
2. kTLS 운영체제 지원
2-1. kTLS를 지원하는 OS
2-2. kTLS를 지원하지 않는 OS
2-3. TLS 프로토콜 및 암호 지원
3. NGINX에서 kTLS 사용
3-1. 커널에 kTLS Load
3-2. FreeBSD에서 kTLS로 NGINX 활성화(Enabling)
3-3. Linux 배포판에서 kTLS로 NGINX Build
3-4. NGINX kTLS 구성
3-5. kTLS가 활성화 확인
4. kTLS로 성능 향상
4-1. 성능 테스트
4-2. 성능 테스트 결과
5. 요약
1. 일반 요구 사항
- 운영체제 – 다음 중 하나
- FreeBSD 13.0+: FreeBSD 13.0+는 OpenSSL 3.0.0+를 통합하기 위한 NGINX의 수동 Build 없이 NGINX에서 kTLS를 지원하는 유일한 OS입니다.
- Linux 커널 버전 4.17 이상에 구축된 Linux 배포판: 가능하면 버전 5.2 이상에 구축된 배포판을 사용하는 것이 좋습니다. (kTLS 지원은 실제로 버전 4.13에서 사용할 수 있지만 OpenSSL 3.0.0에는 커널 헤더 버전 4.17 이상이 필요합니다.)
- OpenSSL: 버전 3.0.0 이상
- NGINX: 버전 1.21.4 이상
Note: NGINX Plus R27 이상은 Linux 기반 운영체제 버전에서 kTLS를 지원하고 NGINX Plus R26 이상은 FreeBSD에서 지원합니다.
2. kTLS 운영체제 지원
2-1. kTLS를 지원하는 OS
NGINX Open Source에서 지원하는 OS 중 다음은 kTLS 및 표시된 암호를 지원합니다. 암호 지원에 대한 자세한 내용은 TLS 프로토콜 및 암호 지원을 참조하세요.
TLSv1.2 ciphers | TLSv1.3 cipher suites | TLS_CHACHA20_POLY1305_SHA256 cipher | Linux kernel version | |
Amazon Linux 2* | ✅ | ✅ | ❌ | 5.10 |
CentOS 8** | ✅ | ❌ | ❌ | 4.18 |
FreeBSD 13.x | ✅ | ✅ | ❌ *** | N/A |
RHEL 8 | ✅ | ❌ | ❌ | 4.18 |
SLES 15 SP2 | ✅ | ✅ | ✅ | 5.3 |
Ubuntu 20.04 LTS | ✅ | ❌ | ❌ | 5.4 |
Ubuntu 21.04 | ✅ | ✅ | ✅ | 5.11 |
Ubuntu 21.10 | ✅ | ✅ | ✅ | 5.13 |
* 커널 버전은 4.14가 아닌 5.10이어야 합니다. kTLS를 지원하지 않는 OS 및 Amazon Linux 2 FAQ 참조
** Upstream Source로 RHEL 8에서 kTLS 지원 상태를 상속합니다.
*** FreeBSD Commit 로그 참조
2-2. kTLS를 지원하지 않는 OS
다음 OS는 아래의 표시된 이유로 kTLS를 지원하지 않습니다.
- Alpine Linux 3.11–3.14: 커널은 CONFIG_TLS=n 옵션으로 Build되어 kTLS를 모듈 또는 커널의 일부로 Build할 수 없습니다.
- Amazon Linux 2: 기본 Amazon Linux 2 AMI의 Linux 커널 버전은 4.14입니다(Amazon Linux 2 FAQ 참조).
- CentOS 7.4+: Linux 커널 버전은 3.10입니다. RHEL 7.4+에서 kTLS 지원 상태를 Upstream Source로 상속합니다.
- Debian 10 및 11: 커널은 CONFIG_TLS=n 옵션으로 Build됩니다(Debian 버그 보고서 로그 참조).
- RHEL 7.4+: Linux 커널 버전은 3.10입니다.
- SLES 12 SP5+: Linux 커널 버전은 4.12입니다.
- Ubuntu 18.04 LTS: Linux 커널 버전은 4.15입니다.
2-3. 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_CHACHA20_POLY1305_SHA256 (kTLS를 지원하는 OS에 지정된 일부 OS에만 해당)
OpenSSL에서 지원하는 TLS 암호가 NGINX Binary에서 활성화되었는지 확인하려면 NGINX를 Build한 디렉토리(예: 홈 디렉토리)에서 openssl-3.0.0/.openssl/bin/openssl 암호 명령을 실행합니다.
3. NGINX에서 kTLS 사용
서론에서 언급했듯이, kTLS는 모든 암호화 및 암호 해독이 커널에서 이루어지기 때문에 NGINX 성능을 향상시킵니다. 데이터는 전송을 위해 네트워크 스택으로 전달되기 전에 커널 공간에서 직접 암호화되므로 TLS 라이브러리로 암호화된 데이터를 User space으로 복사한 다음 다시 전송을 위해 Kernel space으로 복사할 필요가 없습니다.

3-1. 커널에 kTLS Load
최신 FreeBSD 및 Linux 배포판에서 kTLS는 일반적으로 모듈로 Build 됩니다(CONFIG_TLS=m 옵션 사용). NGINX를 시작하기 전에 kTLS 모듈을 커널에 명시적으로 Load 해야 합니다.
- FreeBSD에서 다음 명령을 root 사용자로 실행합니다.
# kldload ktls_ocf.ko
# sysctl kern.ipc.tls.enable=1
FreeBSD 명령 옵션에 대한 자세한 내용은 ktls(4)의 매뉴얼 페이지를 참조하십시오.
- Linux 배포판에서 다음 명령을 root 사용자로 실행합니다.
# modprobe tls
3-2. FreeBSD에서 kTLS로 NGINX 활성화(Enabling)
FreeBSD의 NGINX에서 kTLS 지원을 활성화하려면 Linux 배포판과 동일한 지침을 사용할 수 있습니다. 그러나 다음 단계를 수행하여 FreeBSD Ports Collection의 security/openssl-devel 포트에서 kTLS로 NGINX Build를 활용하는 것이 좋습니다. kTLS 개요를 포함한 자세한 내용은 FreeBSD 웹 사이트에서 커널의 TLS Offload를 참조하십시오.
1. kTLS 지원을 사용하여 OpenSSL 3.0을 구축하고 구성 메뉴에서 적절한 옵션을 선택합니다.
# cd /usr/ports/security/openssl-devel && make config && make install
2. openssl-devel을 기본 SSL 라이브러리로 사용하도록 /etc/make.conf를 수정합니다.
# echo "DEFAULT_VERSIONS+=ssl=openssl-devel" >> /etc/make.conf
3. NGINX Build
# cd /usr/ports/www/nginx-devel && make install
3-3. Linux 배포판에서 kTLS로 NGINX Build
대부분의 최신 Linux 배포판에는 3.0.0 이전의 OpenSSL 버전(일반적으로 버전 1.1)이 포함되어 있습니다. 따라서 OpenSSL 3.0.0을 사용하여 Source에서 NGINX를 Build 해야 합니다.
kTLS 지원을 활성화하는 구성 명령의 두 가지 중요한 옵션은 다음과 같습니다.
--with-openssl=../openssl-3.0.0
--with-openssl-opt=enable-ktls
다른 구성 옵션은 nginx.org에서 제공되는 공식 NGINX Binary 패키지에 포함된 모듈에 대한 것입니다. 대신 사용자 정의 모듈 세트를 지정할 수 있습니다. 현재 NGINX Binary에 사용된 Build 옵션을 보려면 nginx -V를 실행하십시오.
OpenSSL 3.0.0으로 NGINX를 Build하려면 다음 명령을 실행합니다.
$ 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-path=/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-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--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
Note: 결과 NGINX Binary는 OpenSSL 3.0.0 라이브러리와 정적으로 연결됩니다. 나중에 OpenSSL을 패치해야 하는 경우 새 OpenSSL Source Archive를 다운로드하고 압축을 푼 다음 위의 명령을 실행하여 NGINX Binary를 다시 Build 해야 합니다.
3-4. NGINX kTLS 구성
kTLS를 활성화하려면 테스트에 사용된 이 샘플 구성에서와 같이 server{} Context의 옵션 KTLS 매개변수와 함께 ssl_conf_command 지시문을 포함합니다.
worker_processes auto;
error_log /var/log/nginx/error.log debug;
events {}
http {
sendfile on;
server {
listen 443 ssl;
ssl_certificate ssl/example.crt;
ssl_certificate_key ssl/example.key;
ssl_conf_command Options KTLS;
ssl_protocols TLSv1.3;
location / {
root /data;
}
}
}
3-5. kTLS 가 활성화 확인
NGINX가 kTLS를 사용하는지 확인하려면 디버깅 모드를 활성화하고 Error Log에서 BIO_get_ktls_send() 및 SSL_sendfile()을 확인하십시오.
$ grep BIO /var/log/nginx/error.log
2021/11/10 16:02:46 [debug] 274550#274550: *2 BIO_get_ktls_send(): 1
2021/11/10 16:02:49 [debug] 274550#274550: *3 BIO_get_ktls_send(): 1
$ grep SSL_sendfile /var/log/nginx/error.log
2021/11/10 16:02:46 [debug] 274550#274550: *2 SSL_sendfile: 1048576
2021/11/10 16:02:49 [debug] 274550#274550: *3 SSL_sendfile: 1048576
Note: 특히 Production 환경에서 이러한 확인을 수행한 후 디버깅 모드를 비활성화하는 것이 좋습니다. 디버그 로깅은 대량의 쓰기 작업으로 인해 성능이 저하됩니다. 또한 디버그 로그는 방대하며 디스크 파티션에서 사용 가능한 공간을 빠르게 소진할 수 있습니다.
4. kTLS로 성능 향상
과부하(heavy load)가 많은 상태에서 정적 파일 및 캐시 된 응답을 제공할 때 SSL_sendfile()은 User space TLS에 비해 최대 2배까지 처리량을 증가시킬 수 있지만 성능 향상의 크기는 다양한 요인(디스크 성능, 시스템 로드 등)에 따라 크게 달라집니다. 네트워크 카드가 TLS Offload를 지원하는 경우 CPU 사용량을 줄이는 것도 가능합니다.
4-1. 성능 테스트
설정에서 성능 향상을 측정하려면 다음 지침을 사용하여 간단한 One ‑ Thread 테스트를 실행하십시오. 아래에 설명된 대로 테스트 결과에 따르면 특정 조정 없이 최대 30%까지 성능이 향상되었음을 나타냅니다.
사용된 하드웨어 및 소프트웨어:
- AWS t3.medium 인스턴스:
- 4GB RAM
- 20GB 범용 SSD
- Intel® Xeon® Platinum 8259CL CPU(2.50GHz, 2코어)
- FreeBSD 13.0 및 Ubuntu 21.10
- TLS_AES_256_GCM_SHA384 암호화 되어 있는 TLSv1.3
- NGINX 1.21.4, NGINX에서 kTLS 활성화에 지정된 대로 Build 및 구성되었습니다.
테스트를 수행하려면:
1. 디스크 캐시에 완전히 들어가는 대용량 파일을 만듭니다.
# truncate -s 1g /data/1G
2. 이 명령을 실행하여 처리량을 확인합니다. 더 정확한 결과를 얻기 위해 기본 명령을 여러 번 반복합니다. 기본 통계 분석을 위해 출력을 Ministat Utility[FreeBSD][Ubuntu]로 Pipe 합니다.
# for i in 'seq 1 100'; do curl -k -s -o /dev/null -w '%{speed_download}\n' https://localhost/1G | ministat
4-2. 성능 테스트 결과
Ministat의 출력으로 표시되는 다음 테스트 결과에서 각 값은 kBytes/초 단위의 다운로드 속도입니다. 출력은 가독성을 위해 두 줄로 분할됩니다.
kTLS가 없는 FreeBSD 13.0의 처리량:
N Min Max Median ...
x 10 532225 573348 555616 ...
... Avg Stddev
... 555155.6 10239.137
kTLS를 사용하는 FreeBSD 13.0의 처리량:
N Min Max Median ...
x 10 629379 723164 717349 ...
... Avg Stddev
... 708600.4 28304.766
kTLS가 없는 Ubuntu 21.10의 처리량:
N Min Max Median ...
x 10 529199 705720 662354 ...
... Avg Stddev
... 654321.6 48025.103
kTLS를 사용하는 Ubuntu 21.10의 처리량:
N Min Max Median ...
x 10 619105 760208 756278 ...
... Avg Stddev
... 741848.3 43255.246
테스트에서 kTLS는 Ubuntu보다 FreeBSD에서 성능을 더욱 향상시켰습니다. 개선된 비율은 다음과 같습니다.
Min | Max | Median | Avg | |
FreeBSD 13.0 | 18% | 26% | 29% | 28% |
Ubuntu 21.10 | 16% | 8% | 14% | 13% |
5. 요약
NGINX 1.21.4 버전부터에서는 SSL_sendfile()로 정적 파일 및 캐시 된 응답을 제공할 때 kTLS를 지원합니다. 테스트 결과 운영 체제에 따라 성능이 8%에서 29%까지 향상되는 것으로 나타났습니다.
kTLS 및 NGINX의 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.
댓글을 달려면 로그인해야 합니다.