介绍
自从https普及以来,tls的性能开销一直是web的痛,针对这tls的性能调优一直是经久不衰的话题,协议层面比如握手优化、session复用,算法层面比如ChaCha20-Poly1305,硬件层面cpu的硬件支持等
如今,系统层面也有了一种新的优化,就是kTLS(Kernel TLS)。
Kernel TLS 其实就是将原本TLS的过程放到内核中来做,甚至如果网卡本身支持的话可以直接交给网卡。
目前nginx已经支持了ktls,是在 SSL_sendfile() 传输静态文件时引入了 kTLS 支持,毕竟改动不大,所以支持的比较快。(不像http3,已经延期一年了)
要求
kTLS 很早就引入了,但是直到最近也才可用,只要是一直在增加功能,现在各方组件基本已经完善可用了。所以自己尝尝鲜。
要求:
- 内核版本 4.17+
- openssl 3.0.0+
- Nginx 1.21.4+
具体操作系统支持如下:
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 |
但表格中并未列出Ubuntu22.04和RockyLinux9系统,这两款操作系统都是今年才发布的。
另外还要注意一下,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(仅部分操作系统)
下面开始
本次演示基于
- 操作系统:Ubuntu 22.04
- Nginx:nginx-1.23.1
- Openssl:3.0.5
1. 编译Nginx
# 下载nginx源码
wget https://nginx.org/download/nginx-1.23.1.tar.gz
# 下载openssl源码
https://www.openssl.org/source/openssl-3.0.5.tar.gz
# 安装依赖
apt install libpcre3-dev zlib1g-dev libxml2-dev libxslt-dev install libgd-dev
# 编译
./configure \
--user=www-data \
--group=www-data \
--prefix=/usr/share/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-compat \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_v2_module \
--with-http_dav_module \
--with-http_slice_module \
--with-threads \
--with-http_addition_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-openssl=../openssl-3.0.5 \
--with-openssl-opt=enable-ktls \
--with-cc-opt='-g -O2 -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' \
--with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC'
make -j$(nproc --all)
make install
构建参数基本基于Ubuntu22.04原版分发的Nginx。以下异同:
- 不引入额外的源码比如pcre,zlib等通过apt安装前置依赖
- 文件生成路径,完全按照原版参数构建的话,是不会和apt安装的路径一样的
正常apt install nginx的话会安装如下包:
libnginx-mod-http-geoip2 libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream libnginx-mod-stream-geoip2 nginx-common nginx-core
可以看出原版Ubuntu nginx分发的包是拆开的,本次构建只添加了stream相关模块,其他模块未包含
- kTLS 构建参数,就两行
–with-openssl=../openssl-3.0.5
实际上openssl用ubuntu原本分发的openssl-dev就行,不过由于openssl是关键,未避免不必要的情况,采用源码构建
–with-openssl-opt=enable-ktls
启用kTLS
注意:构建完成后还需建立如下目录,构建过程中不会自动生成
mkdir -p /var/lib/nginx/body
mkdir -p /var/lib/nginx/fastcgi
mkdir -p /var/lib/nginx/proxy
mkdir -p /var/lib/nginx/scgi
mkdir -p /var/lib/nginx/uwsgi
如果需要查看openssl支持的TLS密码套件,在openssl源码目录下执行:
.openssl/bin/openssl ciphers
2. 加载ktls模块
# 手动加载
modprobe tls
# 开机挂载
echo tls > /etc/modules-load.d/modules.conf
3. Nginx配置文件
在原来配置ssl相关地方增加一行
ssl_conf_command Options KTLS;
可选择在http或者server中添加
4. 验证
日志开启debug,需要构建参数中添加 –with-debug,否则设置了也不生效。
出现BIO_get_ktls_send 和 SSL_sendfile 代表生效
tail -f /var/log/nginx/error.log | grep -E "BIO_get_ktls_send|SSL_sendfile"
2022/09/11 20:42:09 [debug] 980#980: *43 BIO_get_ktls_send(): 1
2022/09/11 20:42:09 [debug] 982#982: *44 BIO_get_ktls_send(): 1
2022/09/11 20:42:10 [debug] 982#982: *40 SSL_sendfile: 3304
2022/09/11 20:42:29 [debug] 982#982: *51 BIO_get_ktls_send(): 1
2022/09/11 20:42:30 [debug] 982#982: *51 SSL_sendfile: 3304
2022/09/11 20:42:31 [debug] 980#980: *53 BIO_get_ktls_send(): 1
2022/09/11 20:42:49 [debug] 980#980: *57 BIO_get_ktls_send(): 1
参考
https://juejin.cn/post/7104795466809753607
https://www.nginx-cn.net/blog/improving-nginx-performance-with-kernel-tls/#oss-without-support