1

Linux 的 sendfile 系统调用是最快的发送静态文件的方式。它通过在内核中直接拷贝数据,避免了使用 read / write 导致的用户态、内核态的上下文切换,极大的提升了传输效率。nginx 也很早就支持了 sendfile 指令的使用。

然而避免了用户态、内核态切换也就意味着 sendfile 只能发送原始未加密的数据,nginx 用到的 OpenSSL 的加密方法是运行在用户态的。

这就产生了一个矛盾:想使用 sendfile,就不能启用 https,想使用 https 就不能用 sendfile。直到 kTLS 的出现解决了这个矛盾。

kTLS 简单理解就是运行在内核中的加密算法,在内核态拷贝数据时可以同时做数据加密。OpenSSL 3.0 加入了 SSL_sendfile 以支持 kTLS 的使用,nginx 1.14.4 支持了 SSL_sendfile。所有条件已经凑齐,万事俱备只欠东风。接下来就让我们编译一套支持 SSL_sendfile 的 nginx 版本尝鲜

  1. kTLS 是内核特性,需要比较新的内核版本,CentOS 7 自带的 Linux 3.x 肯定是不能用的。首先需要升级 Linux 内核。我使用的是 elrepo 编译好的包,直接上最新版本 5.x sudo yum install kernel-ml kernel-ml-headers (注意 OpenSSL 的 kTLS 支持需要最新的内核头文件,所以 kernel-ml-headers 也是必须的)
  2. 重启系统 sudo reboot,启用 kTLS 内核模块支持 sudo modprobe tls。注意这一步是在运行 nginx 的服务器上执行的命令,如果你需要把编译好的 nginx 复制给其他服务器使用,那么所有服务器都需要启用 kTLS。相反编译 nginx 的机器如果不运行就不需要。
  3. 下载最新的 OpenSSL 源码。我直接使用的 git 版本。git clone https://github.com/openssl/openssl.git
  4. 编译 nginx。configure 命令需要加入参数 --with-openssl=/path/to/openssl --with-openssl-opt="enable-ktls enable-zlib enable-ec_nistp_64_gcc_128"
  5. 配置 nginx。http 块添加 sendfile on; ssl_conf_command Options KTLS;。当然其他 https 配置也是必须的

重启 nginx,启用 debug 日志模式。检查出现了 SSL_sendfile 日志说明一切正常

image.png


CarterLi
1.3k 声望102 粉丝