传输层安全性(TLS)是一种极为流行的加密协议。 在内核中实现 TLS(kTLS)可显著减少用户空间和内核之间复制操作的需要,从而提高性能。
结合 kTLS 和sendfile()
意味着数据在传递到网络堆栈进行传输之前直接在内核空间中加密。 这样就无需将数据复制到用户空间以由 TLS 库加密,然后再复制回内核空间进行传输。kTLS 还支持将 TLS 处理卸载到硬件,包括将 TLS 对称加密处理卸载到网络设备。
现代 Linux 和 FreeBSD 内核支持将 TLS 卸载到内核,现在 NGINX Open Source 也支持! NGINX 1.21.4 在使用SSL_sendfile()
提供静态文件和缓存响应时引入了对 kTLS 的支持,这可以极大地提高性能。 如下所述,内核和 OpenSSL 都必须使用 kTLS 构建,NGINX 才能使用SSL_sendfile()
。
在这篇博客中,我们详细介绍了哪些操作系统和 OpenSSL 版本支持 kTLS,并展示了如何为 kTLS 构建和配置内核和 NGINX。 为了让您了解 kTLS 所带来的性能改进,我们还分享了在 FreeBSD 和 Ubuntu 上测试的规格和结果。
注意: kTLS 实现相当新并且发展迅速。 本博客描述了截至 2021 年 11 月对 kTLS 的支持,但请留意nginx.org和NGINX 博客 <.htmla> 上有关此处提供的信息和说明的变更的公告。
操作系统 - 以下任一:
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 或更高版本(主线)
[编辑器- NGINX Plus R27及更高版本在符合条件的基于 Linux 的操作系统版本上支持 kTLS;NGINX Plus R26 及更高版本在符合条件的 FreeBSD 版本上支持它。 有关支持的操作系统的详细信息,请参阅 NGINX Plus版本页面。
截至 2021 年 11 月,在NGINX 开源支持的操作系统中,以下操作系统支持 kTLS 和指示的密码。 有关密码支持的详细信息,请参阅TLS 协议和密码支持。
TLSv1.2 密码 | TLSv1.3 密码套件 |
TLS_CHACHA20_POLY1305_SHA256 密码 |
Linux 内核版本 | |
---|---|---|---|---|
亚马逊 Linux 2 * | ✅ | ✅ | ❌ | 5.10 |
CentOS 8 ** | ✅ | ❌ | ❌ | 4.18 |
FreeBSD 13.x | ✅ | ✅ | ❌ *** | 不适用 |
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:
CONFIG_TLS=n
选项构建的,该选项禁止将 kTLS 构建为模块或内核的一部分。CONFIG_TLS=n
选项构建的(请参阅Debian 错误报告日志)。如上所述,支持 kTLS 的操作系统对 TLS 协议和密码的支持有所不同。
使用 TLSv1.2,kTLS 模块支持以下密码:
适用于 AES128-GCM 的 SHA256
适用于 AES256-GCM 的 SHA384
哈希算法
椭圆曲线加密
使用 TLSv1.3,kTLS 模块支持以下密码套件:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
(仅限部分操作系统,如支持 kTLS 的操作系统中所述)要验证您的 NGINX 二进制文件中启用了 OpenSSL 支持的哪些 TLS 密码,请在构建 NGINX 的目录(例如,您的主目录)中运行openssl-3.0.0/.openssl/bin/openssl
ciphers
命令。
正如介绍中所提到的,kTLS 提高了 NGINX 的性能,因为所有加密和解密都在内核中进行。 数据直接在内核空间加密 - 然后传递给网络堆栈进行传输 - 无需将数据复制到用户空间进行 TLS 库加密,然后再复制回内核空间进行传输。
在现代 FreeBSD 和 Linux 发行版中,kTLS 通常作为模块构建(使用CONFIG_TLS=m
选项)。 在启动 NGINX 之前,您必须明确将 kTLS 模块加载到内核中。
在 FreeBSD 上,以root
用户身份运行以下命令:
# kldload ktls_ocf.ko # sysctl kern.ipc.tls.enable=1
有关 FreeBSD 命令选项的详细信息,请参阅ktls(4)
的手册页。
在 Linux 发行版上,以root
用户身份运行以下命令:
# modprobe tls
要在 FreeBSD 上的 NGINX 中启用 kTLS 支持,您可以使用与 Linux 发行版相同的说明。 但是,我们建议您执行以下步骤,以利用FreeBSD 端口集合中的security/openssl-devel端口中带有 kTLS 的 NGINX 构建。 有关更多信息,包括 kTLS 概述,请参阅 FreeBSD 网站上的内核中的 TLS 卸载。
构建支持 kTLS 的 OpenSSL 3.0,在配置菜单中选择适当的选项:
# cd /usr/ports/security/openssl-devel && 进行配置 && 进行安装
修改/etc/make.conf以使用openssl-devel作为默认 SSL 库:
#回显 "DEFAULT_VERSIONS+=ssl=openssl-devel" >> /etc/make.conf
构建 NGINX:
# cd /usr/ports/www/nginx-devel && 进行安装
大多数当前 Linux 发行版都包含早于 3.0.0 的 OpenSSL 版本(通常是 1.1 版本)。 因此您需要使用 OpenSSL 3.0.0 从源代码构建 NGINX。
配置
命令中启用 kTLS 支持的两个关键选项是:
--with-openssl=../openssl-3.0.0
--with-openssl-opt=enable-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-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 二进制文件。
要启用 kTLS,请在server{}
上下文中包含带有Options
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;
}
}
}
要验证 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 [debug] 274550#274550: *2 SSL_sendfile: 1048576 2021/11/10 16:02:49 [调试] 274550#274550:*3 SSL_sendfile: 1048576
笔记: 我们建议您在进行这些检查后禁用调试模式,尤其是在生产环境中。 由于大量的写入操作,调试日志会导致性能损失;此外,调试日志可能非常庞大,并会很快耗尽磁盘分区上的可用空间。
在高负载下提供静态文件和缓存响应时, SSL_sendfile()
与用户空间 TLS 相比可将吞吐量提高 2 倍,但性能提升的大小在很大程度上取决于各种因素(磁盘性能、系统负载等)。 如果您的网卡支持 TLS 卸载,也可以减少 CPU 的使用率。
要测量您的设置的性能提升,请按照以下说明运行简单的单线程测试。 如下所述,我们的测试结果表明,无需任何特殊调整,性能即可提升近 30%。
使用的硬件和软件:
TLS_AES_256_GCM_SHA384
密码套件的 TLSv1.3要进行测试:
创建一个完全适合磁盘缓存的大文件:
#截断 -s 1g /数据/1G
运行此命令来检查吞吐量;基本命令重复多次以获得更准确的结果。 将输出通过管道传输到ministat
实用程序[ FreeBSD ][ Ubuntu ] 进行基本统计分析。
#对于'seq 1 100'中的i;执行curl -k -s -o /dev/null -w'%{speed_download} \n'https://localhost/1G | ministat
以下测试结果以ministat
的输出形式呈现,每个值都是以 kBytes/秒为单位的下载速度。 为了便于阅读,输出分为两行。
不使用 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 对 FreeBSD 的性能提升比 Ubuntu 更大。 改善百分比如下:
分钟 | 最大限度 | 中位数 | 平均 | |
---|---|---|---|---|
FreeBSD 13.0 | 18% | 26% | 29% | 28% |
Ubuntu 21.10 | 16% | 8% | 14% | 13% |
NGINX 1.21.4 在使用SSL_sendfile()
提供静态文件和缓存响应时引入了对 kTLS 的支持。 我们的测试表明,性能提高了 8% 到 29%,具体取决于操作系统。
我们有兴趣了解您使用 kTLS 和 NGINX 的经验,尤其是您在其他操作系统上测试的结果! 请在下面的评论部分分享。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”