2

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

 2 years ago
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.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/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK