传输层安全 (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%,具体取决于操作系统。
我们有兴趣了解您使用 kTLS 和 NGINX 的体验,尤其是您在其他操作系统上的测试结果!请在下面的评论部分分享它们。
via https://www.nginx.com/blog/improving-nginx-performance-with-kernel-tls/