在 CentOS 下為 nginx 啟用 SSL_sendfile 支援

CarterLi發表於2021-12-27

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

相關文章