使用Kernel TLS 和 SSL_sendfile( ) 提高 NGINX 性能
277 次浏览
发表于 2022-04-15 11:44

原文作者:Mikhail Isachenkov of F5, Timo Stark of F5
原文链接:使用Kernel TLS 和 SSL_sendfile( ) 提高 NGINX 性能 - NGINX
转载来源:NGINX 官方网站

TLS(传输层安全协议)是一种极为受欢迎的加密协议。在内核 (kernel) 中实施 TLS (即 kTLS) 可显著降低在用户空间与内核之间复制操作的需求,从而提高 NGINX 的性能。  

通过结合使用 kTLS 和 sendfile(),数据可以直接在内核空间加密,然后再传递到网络堆栈进行传输。这使得我们不再需要将数据复制到用户空间、利用 TLS 库进行加密、再返回内核空间进行传输的这一过程。kTLS 还可以将 TLS 的处理过程卸载到硬件,包括将 TLS 对称加密处理任务卸载到网络设备

现代 Linux 和 FreeBSD 内核支持将 TLS 卸载到内核,而 NGINX 开源版现在也同样能做到!NGINX 1.21.4 在使用 SSL_sendfile() 传输静态文件时引入了 kTLS 支持,可以极大地改善性能。如下所述,内核和 OpenSSL 只有采用 kTLS 构建,才能让 NGINX 使用 SSL_sendfile()。

本文详细介绍了支持 kTLS 的操作系统以及 OpenSSL 版本,并展示了如何针对 kTLS 构建和配置内核与 NGINX。为了向您展示 kTLS 的性能改善效果,我们还将分享在 FreeBSD 和 Ubuntu 上进行测试的具体说明和结果数据。

注:kTLS 的实施这一新兴事物正在迅速发展中。本文描述了截至 2021 年 11 月 NGINX 对 kTLS 的支持情况,但本文提供的信息和说明可能会在之后进行更新,请随时关注 nginx.orgNGINX 博客上的公告。


通用要求

  • 操作系统 —— 以下任一一个:

    FreeBSD 13.0+。截至 2021 年 11 月,FreeBSD 13.0+ 是唯一一个在 NGINX 中支持 kTLS 的操作系统,且无需手动构建 NGINX 即可整合 OpenSSL 3.0.0+。请参阅 在 FreeBSD 上启用支持 kTLS 的 NGINX。  

    可以使用在 Linux 内核版本 4.17 或更高版本上构建的 Linux 发行版,但我们建议尽可能使用在版本 5.2 或更高版本上构建的发行版。(实际上,版本 4.13 便提供了 kTLS 支持,但 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 内核版本
Amazon 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(请参阅 Amazon Linux 2 常见问题解答)的 Linux 内核版本是 4.14。
  • 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 密码,请运行构建 NGINX 的目录(例如主目录)中的 openssl-3.0.0/.openssl/bin/openssl ciphers 命令。


启用 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 端口集合的 openssl-devel 树中使用支持 kTLS 的 NGINX。有关更多信息(包括 kTLS 概述),请参阅 FreeBSD 网站上的将 TLS 卸载到内核
  1. 构建支持 kTLS 的 OpenSSL 3.0,在配置菜单中选择适当的选项:
    # cd /usr/ports/security/openssl-devel && make config && make install
  2. 修改 /etc/make.conf,将 openssl-devel 用作 SSL 库:
    # echo "DEFAULT_VERSIONS+=ssl=openssl-devel >> /etc/make.conf
  3. 构建 NGINX:
    # cd /usr/ports/security/openssl-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-ktl
另一个 configure 选项面向 NGINX 官方二进制包(请见 nginx.org)中的模块。您还可以指定一组自定义模块。如要查看当前 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,在 server{}中的 ssl_conf_command 指令中添加 Options KTLS 参数,如我们的测试中使用的示例配置:
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 使用率。

测试性能

如要测量您的设置的性能提升情况,可以依循以下说明来运行简单的单线程测试。如下所述,我们的测试结果表明,无需进行任何特定调整,kTLS 即可将性能提升近 30%。

使用的硬件和软件:

  • AWS t3.medium 实例采用了:
  • 4 GB RAM
  • 20 GB 通用 SSD
  • 英特尔® 至强® 白金 8259CL CPU,2.50GHz 双核处理器
  • FreeBSD 13.0 和 Ubuntu 21.10
  • TLSv1.3,采用 TLS_AES_256_GCM_SHA384 密码套件
  • NGINX 1.21.4,根据启用 NGINX 中的 kTLS 部分的要求构建和配置。
执行测试的方法:
  1. 创建一个完全适合磁盘缓存的大文件:
    # truncate -s 1g /data/1G
  2. 运行以下命令检查吞吐量;多次重复执行基本命令以获得更准确的结果。将输出结果输出到 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 的输出结果表示,每个值都是下载速度,单位是 kBytes/秒。

不支持 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 相比,FreeBSD 上的 kTLS 提升的性能更高。性能改进比例如下:
 最小值最大值中位数平均数
FreeBSD 13.0 18%26%29%28%
Ubuntu 21.10 16%8%14%13%


结语

NGINX 1.21.4 在使用 SSL_sendf ile() 提供静态文件时引入了 kTLS 支持。我们的测试表明,NGINX 性能可提高 8% 到 29%,具体因操作系统而异。

我们很想知道您的 kTLS 和 NGINX 使用体验,尤其是您在其他操作系统上的测试结果!您可以在下方的评论区中分享您的结果。


更多资源

想要更及时全面地获取NGINX相关的技术干货、互动问答、系列课程、活动资源?

请前往NGINX开源社区:


如果您觉得不错,就打赏支持一下吧〜
已有 0 人进行打赏
点击标签,发现更多精彩
发表评论
  • 明月登楼

    悲催的我的服务器无法下载openssl

    2022-06-08 16:35
    0
    回复
发表者

NGINX官方账号

NGINX官方账号

  • 96

    文章

  • 2

    关注

  • 156

    粉丝

活动推荐
Copyright 公安部网络安全保卫局 All Rights Reserved
京公网安备 11010502047880号    京ICP备05070602号