传输层安全 (TLS) 是一种非常流行的加密协议。在内核 (kTLS) 中实现 TLS 通过显着减少用户空间和内核之间的复制操作需求来提高性能。
结合 kTLS 和sendfile()意味着数据在传递到网络堆栈进行传输之前直接在内核空间中加密。这消除了将数据复制到用户空间以通过 TLS 库加密,然后再返回内核空间进行传输的需要。kTLS 还支持将 TLS 处理卸载到硬件,包括将 TLS 对称加密处理卸载到网络设备。
现代 Linux 和 FreeBSD 内核支持将 TLS 卸载到内核,现在 NGINX 开源也支持!NGINX 1.21.4在使用 提供静态文件时引入了对 kTLS 的支持SSL_sendfile(),这可以极大地提高性能。如下详述,内核和 OpenSSL 都必须使用 kTLS 构建,NGINX 才能使用SSL_sendfile().
在这详细介绍了哪些操作系统和 OpenSSL 版本支持 kTLS,并展示了如何为 kTLS 构建和配置内核和 NGINX。为了让您了解可以从 kTLS 中获得的性能改进,还分享了在 FreeBSD 和 Ubuntu 上测试的规范和结果。
注意: kTLS 实现是相当新的并且发展迅速。本博客介绍了截至 2021 年 11 月对 kTLS 的支持,但请留意nginx.org和NGINX 博客上关于此处提供的信息和说明的更改的公告。
一般要求
-
操作系统——以下任一项:
-
FreeBSD 13.0+。截至 2021 年 11 月,FreeBSD 13.0+ 是唯一一个在 NGINX 中支持 kTLS 的操作系统,无需手动构建 NGINX 以合并 OpenSSL 3.0.0+。请参阅在 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 或更高版本(主线)
操作系统支持
支持 kTLS 的操作系统
截至 2021 年 11 月,在NGINX 开源支持的操作系统中,以下支持 kTLS 和指定的密码。有关密码支持的详细信息,请参阅TLS 协议和密码支持。
TLSv1.2 密码 | TLSv1.3 密码套件 |
TLS_CHACHA20_POLY1305_SHA256 密码 | Linux内核版本 | |
---|---|---|---|---|
亚马逊 Linux 2 * | ✅ | ✅ | ❌ | 5.10 |
CentOS 8 ** | ✅ | ❌ | ❌ | 4.18 |
FreeBSD 13.0 | ✅ | ✅ | ❌ *** | 不适用 |
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 |
*内核版本必须是 5.10,而不是 4.14;请参阅不支持 kTLS 的操作系统和Amazon Linux 2 常见问题
**从 RHEL 8 继承其 kTLS 支持状态作为其上游源
***请参阅FreeBSD 提交日志
不支持 kTLS 的操作系统
以下操作系统不支持 kTLS,原因如下:
- Alpine Linux 3.11–3.14 – 内核是使用该CONFIG_TLS=n选项构建的,该选项禁止将 kTLS 构建为模块或内核的一部分。
- Amazon Linux 2 – 默认 Amazon Linux 2 AMI 的 Linux 内核版本为 4.14(请参阅Amazon Linux 2 常见问题解答)。
- 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在他们对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 的操作系统中所述)
要验证在您的 NGINX 二进制文件中启用了 OpenSSL 支持的哪些 TLS 密码,请openssl-3.0.0/.openssl/bin/openssl ciphers在您构建 NGINX 的目录(例如,您的主目录)中运行该命令。
在 NGINX 中启用 kTLS
正如介绍中提到的,kTLS 提高了 NGINX 的性能,因为所有的加密和解密都在内核中进行。数据直接在内核空间加密——在传递到网络堆栈进行传输之前——无需将数据复制到用户空间由 TLS 库加密,然后再回到内核空间进行传输。
在内核中加载 kTLS
在现代 FreeBSD 和 Linux 发行版中,kTLS 通常被构建为一个模块(带有CONFIG_TLS=m选项)。在启动 NGINX 之前,您必须将 kTLS 模块显式加载到内核中。
-
在 FreeBSD 上,以root用户身份运行以下命令:
# kldload ktls ocf # sysctl kern.ipc.tls.enable=1
有关 FreeBSD 命令选项的详细信息,请参阅ktls(4).
-
在 Linux 发行版上,以root用户身份运行以下命令:
# modprobe tls
在 FreeBSD 上使用 kTLS 启用 NGINX
要在 FreeBSD 上的 NGINX 中启用 kTLS 支持,您可以使用与Linux 发行版相同的说明。但是,建议您执行以下步骤以利用FreeBSD 端口集合中security/openssl-devel端口中的kTLS 构建 NGINX 。有关更多信息,包括 kTLS 的概述,请参阅FreeBSD 网站上的内核中的 TLS 卸载。
-
构建支持 kTLS 的 OpenSSL 3.0,在配置菜单中选择适当的选项:
# cd /usr/ports/security/openssl-devel && make config && make install
-
修改/etc/make.conf以使用openssl-devel作为默认 SSL 库:
# echo "DEFAULT_VERSIONS+=ssl=openssl-devel >> /etc/make.conf
-
构建 NGINX:
# cd /usr/ports/www/nginx-devel && make install
在 Linux 发行版上使用 kTLS 构建 NGINX
大多数当前的 Linux 发行版都包含早于 3.0.0(通常为 1.1 版)的 OpenSSL 版本。因此,您需要使用 OpenSSL 3.0.0 从源代码构建 NGINX。
configure启用 kTLS 支持的命令的两个关键选项是:
- --with-openssl=../openssl-3.0.0
- --with-openssl-opt=enable-ktls
其他configure选项适用于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-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
注意:生成的 NGINX 二进制文件与 OpenSSL 3.0.0 库静态链接。如果以后需要修补 OpenSSL,则必须下载并解压新的 OpenSSL 源存档,然后运行上述命令以重建 NGINX 二进制文件。
配置 NGINX
要启用 kTLS,请在上下文中包含ssl_conf_command带有Options KTLS参数的指令server{},如用于的测试的示例配置:
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; } } }
验证 kTLS 是否已启用
要验证NGINX使用KTLS,使调试模式和检查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
注意:建议您在进行这些检查后禁用调试模式,尤其是在生产环境中。由于大量的写操作,调试日志会导致性能损失;此外,调试日志可能会很大,并且会很快耗尽磁盘分区上的可用空间。
使用 kTLS 提高性能
在重负载下提供静态文件时,与用户空间 TLS 相比,吞吐量最多SSL_sendfile()可提高 2倍,但性能提升的大小在很大程度上取决于各种因素(磁盘性能、系统负载等)。如果您的网卡支持 TLS 卸载,还可以减少 CPU 使用率。
测试性能
要测量设置的性能提升,请使用以下说明运行简单的单线程测试。如下详述,的测试结果表明,无需任何特定调整即可将性能提升近 30%。
使用的硬件和软件:
- AWS t3.medium 实例具有:
- 4 GB 内存
- 20 GB 通用固态硬盘
- 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 中的规定构建和配置。
要执行测试:
-
创建一个完全适合磁盘缓存的大文件:
# truncate -s 1g /data/1G
-
运行此命令以检查吞吐量;基本命令重复多次以获得更准确的结果。将输出通过管道传送到ministat实用程序 [ FreeBSD ][ Ubuntu ] 以进行基本的统计分析。
# for i in 'seq 1 100'; do curl -k -s -o /dev/null -w '%{speed_download}n' https://localhost/1G | ministat
性能测试结果
在测试的以下结果中,显示为 的输出ministat,每个值都是以千字节/秒为单位的下载速度。
没有 kTLS 的 FreeBSD 13.0 的吞吐量:
N Min Max Median Avg Stddev x 10 532225 573348 555616 555155.6 10239.137
带有 kTLS 的 FreeBSD 13.0 的吞吐量:
N Min Max Median Avg Stddev x 10 629379 723164 717349 708600.4 28304.766
没有 kTLS 的 Ubuntu 21.10 的吞吐量:
N Min Max Median Avg Stddev x 10 529199 705720 662354 654321.6 48025.103
带有 kTLS 的 Ubuntu 21.10 的吞吐量:
N Min Max Median Avg Stddev x 10 619105 760208 756278 741848.3 43255.246
在的测试中,与 Ubuntu 相比,kTLS 使用 FreeBSD 提高了性能。百分比改进如下:
最小 | 最大限度 | 中位数 | 平均 | |
---|---|---|---|---|
FreeBSD 13.0 | 18% | 26% | 29% | 28% |
Ubuntu 21.10 | 16% | 8% | 14% | 13% |
概括
NGINX 1.21.4 在使用SSL_sendfile(). 的测试表明,性能提高了 8% 到 29%,具体取决于操作系统。