传输层安全性(TLS)是一种应用非常广泛的加密协议。在内核中实现TLS(kTLS),可显著减少用户空间与内核之间的数据复制操作,从而提升性能。
结合使用kTLS和sendfile(),数据会先直接在内核空间中加密,再传递到网络协议栈进行传输。这样就无需将数据复制到用户空间,由TLS库加密后再复制回内核空间进行传输。kTLS还支持将TLS处理卸载到硬件,包括将TLS对称加密处理卸载到网络设备。
现代Linux和FreeBSD内核支持将TLS处理卸载到内核,现在NGINX Open Source也支持这一功能。NGINX 1.21.4新增了对kTLS的支持,可在使用SSL_sendfile()提供静态文件和缓存响应时显著提升性能。如下文所述,内核和OpenSSL都必须在构建时启用kTLS,NGINX才能使用SSL_sendfile()。
本文将详细介绍支持kTLS的操作系统和OpenSSL版本,并说明如何针对kTLS构建和配置内核及NGINX。为帮助您了解kTLS可能带来的性能提升,我们还将分享在FreeBSD和Ubuntu上进行测试时所用的配置及测试结果。
注意:kTLS实现尚处于早期阶段,并且发展迅速。本博客介绍了截至2021年11月对kTLS的支持情况,但请留意nginx.org和NGINX博客<.htmla>发布的公告,以了解本文所提供信息和说明的变更。
一般要求
- 操作系统:以下任一项
- FreeBSD 13.0+。截至2021年11月,FreeBSD 13.0+是唯一无需手动构建NGINX以集成OpenSSL 3.0.0+,即可在NGINX中支持kTLS的操作系统。请参阅“在FreeBSD上为NGINX启用kTLS”。
- 基于 Linux 内核 4.17 或更高版本构建的 Linux 发行版,但条件允许时,建议使用基于 5.2 或更高版本构建的发行版。(实际上,4.13 版本已支持 kTLS,但 OpenSSL 3.0.0 要求内核头文件版本为 4.17 或更高版本。)
- OpenSSL,版本3.0.0或更高版本
- NGINX,版本1.21.4或更高版本(主线版)[编辑:NGINX Plus R27及更高版本在符合条件的Linux操作系统版本上支持kTLS;NGINX Plus R26及更高版本在符合条件的FreeBSD版本上支持kTLS。有关受支持操作系统的详细信息,请参阅NGINX Plus的“版本发布”页面。]
操作系统支持
支持kTLS的操作系统
截至2021年11月,在NGINX Open Source支持的操作系统中,以下操作系统支持kTLS及所列密码套件。有关密码套件支持的详细信息,请参阅“TLS协议和密码套件支持”。
| TLSv1.2 密码 | TLSv1.3 密码套件 | TLS_CHACHA20_POLY1305_SHA256 密码 | Linux 内核版本 | |
|---|---|---|---|---|
| Amazon Linux 2* | ✅ | ✅ | ❌ | 5.10 |
| CentOS 8** | ✅ | ❌ | ❌ | 4.18 |
| FreeBSD 13.x | ✅ | ✅ | ❌ *** | 不适用 |
| 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,因此沿用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+,因此沿用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-SHA256AES256-GCM-SHA384ECDHE-RSA-AES128-GCM-SHA256ECDHE-RSA-AES256-GCM-SHA384
对于TLSv1.3,kTLS模块支持以下密码套件:
TLS_AES_128_GCM_SHA256TLS_AES_256_GCM_SHA384TLS_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.ko# sysctl kern.ipc.tls.enable=1- 有关FreeBSD命令选项的详细信息,请参阅
ktls(4)手册页。 - 在Linux发行版上,以
root用户身份运行此命令:
# modprobe tls在FreeBSD上为NGINX启用kTLS
要在FreeBSD上的NGINX中启用kTLS支持,可以使用与Linux发行版相同的说明。不过,建议按照以下步骤操作,以使用security/openssl-devel port中支持kTLS的NGINX构建版本。该port位于FreeBSD Ports Collection中。有关更多信息(包括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发行版附带的OpenSSL版本低于3.0.0(通常为1.1版)。因此,需要使用OpenSSL 3.0.0从源代码构建NGINX。
用于启用kTLS支持的两个关键configure命令选项是:
--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,请在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.log2021/11/10 16:02:46 [debug] 274550#274550: *2 BIO_get_ktls_send(): 12021/11/10 16:02:49 [debug] 274550#274550: *3 BIO_get_ktls_send(): 1 $ grep SSL_sendfile /var/log/nginx/error.log2021/11/10 16:02:46 [debug] 274550#274550: *2 SSL_sendfile: 10485762021/11/10 16:02:49 [debug] 274550#274550: *3 SSL_sendfile: 1048576注意:完成这些检查后,建议禁用调试模式,尤其是在生产环境中。调试日志记录会产生大量写入操作,从而降低性能;此外,调试日志可能非常庞大,并迅速耗尽磁盘分区的可用空间。
使用kTLS提升性能
在高负载下提供静态文件和缓存响应时,SSL_sendfile()可使吞吐量最高提升至 2 倍(与用户空间TLS相比),但实际性能提升幅度在很大程度上取决于多种因素(磁盘性能、系统负载等)。如果网卡支持TLS卸载,还可降低CPU使用率。
测试性能
要衡量您的配置可获得的性能提升,请按照以下说明运行简单的单线程测试。如下文所述,我们的测试结果表明,无需任何特定调优,性能提升幅度可接近30%。
使用的硬件和软件:
- AWS t3.medium实例,配置如下:
- 4 GB RAM
- 20 GB通用型SSD
- Intel® Xeon® Platinum 8259CL CPU,主频 2.50 GHz,配备 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# 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 ...x 10 532225 573348 555616 ... ... Avg Stddev ... 555155.6 10239.137启用kTLS的FreeBSD 13.0吞吐量:
N Min Max Median ...x 10 629379 723164 717349 ... ... Avg Stddev ... 708600.4 28304.766未启用kTLS时Ubuntu 21.10的吞吐量:
N Min Max Median ...x 10 529199 705720 662354 ... ... Avg Stddev ... 654321.6 48025.103启用kTLS的Ubuntu 21.10吞吐量:
N Min Max Median ...x 10 619105 760208 756278 ... ... Avg Stddev ... 741848.3 43255.246在我们的测试中,kTLS在FreeBSD上的性能提升幅度高于Ubuntu。具体提升百分比如下:
| 最小值 | 最大值 | 中位数 | 平均值 | |
|---|---|---|---|---|
| FreeBSD 13.0 | 18% | 26% | 29% | 28% |
| Ubuntu 21.10 | 16% | 8% | 14% | 13% |
总结
NGINX 1.21.4新增了对kTLS的支持,可在使用SSL_sendfile()提供静态文件和缓存响应时启用。测试结果显示,性能提升幅度为8%至29%,具体取决于操作系统。
我们很想了解您使用kTLS和NGINX的体验,尤其是在其他操作系统上的测试结果。欢迎在下方评论区分享。
相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
