使用内核 TLS 和 SSL_sendfile() 提高 NGINX 性能
source link: https://blog.p2hp.com/archives/8286
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
使用内核 TLS 和 SSL_sendfile() 提高 NGINX 性能
传输层安全 (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/
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK