使用内核 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.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 或更高版本构建的发行版。(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 模块支持以下密码套件:

要验证在您的 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 卸载

  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/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 中的规定构建和配置。

要执行测试:

  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,每个值都是以千字节/秒为单位的下载速度。

没有 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/

使用内核 TLS 和 SSL_sendfile() 提高 NGINX 性能
标签: