NGINX.COM

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 ❌ *** N/A
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/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 官方二进制包(请见 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_sendfile() 提供静态文件时引入了 kTLS 支持。我们的测试表明,NGINX 性能可提高 8% 到 29%,具体因操作系统而异。

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

Hero image
免费白皮书:
NGINX 企阅版全解析

助力企业用户规避开源治理风险,应对开源使用挑战

关于作者

Mikhail Isachenkov

关于作者

Timo Stark

Professional Services Engineer

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。