ブログ | NGINX

カーネル TLS と SSL_sendfile() による NGINX パフォーマンスの向上

NGINX-F5 水平黒タイプ RGB の一部
ミハイル・イサチェンコフ サムネイル
ミハイル・イサチェンコフ
2021年11月11日公開

トランスポート層セキュリティ (TLS) は非常に人気のある暗号化プロトコルです。 カーネルに TLS を実装する (kTLS) と、ユーザー空間とカーネル間のコピー操作の必要性が大幅に減少し、パフォーマンスが向上します。

kTLS とsendfile()を組み合わせると、データはネットワーク スタックに渡されて送信される前に、カーネル空間で直接暗号化されます。 これにより、TLS ライブラリで暗号化するデータをユーザー空間にコピーし、その後カーネル空間に戻して送信する必要がなくなります。kTLS では、TLS対称暗号化処理をネットワーク デバイスにオフロードするなど、TLS 処理をハードウェアにオフロードすることもできます。

最新の Linux および FreeBSD カーネルはカーネルへの TLS のオフロードをサポートしており、NGINX Open Source でも同様にサポートされるようになりました。 NGINX 1.21.4 では、 SSL_sendfile()を使用して静的ファイルとキャッシュされた応答を提供するときにkTLS のサポートが導入され、パフォーマンスが大幅に向上します。 以下に詳述するように、NGINX がSSL_sendfile()を使用するには、カーネルと OpenSSL の両方が kTLS を使用してビルドされている必要があります。

このブログでは、どのオペレーティング システムと OpenSSL バージョンが kTLS をサポートしているかを詳しく説明し、kTLS 用にカーネルと NGINX を構築および構成する方法を示します。 kTLS で期待できるパフォーマンスの向上についてご理解いただけるよう、FreeBSD と Ubuntu でのテストの仕様と結果も共有します。

注: kTLS 実装は非常に新しいものであり、急速に進化しています。 このブログでは、2021 年 11 月時点での kTLS のサポートについて説明していますが、ここで提供されている情報と手順の変更については、 nginx.orgNGINX ブログ<.htmla> での発表に注意してください。

一般的な要件

  • オペレーティング システム – 次のいずれか:

    • FreeBSD 13.0以降。 2021 年 11 月現在、OpenSSL 3.0.0 以降を組み込むために NGINX を手動でビルドしなくても、NGINX で kTLS をサポートする OS は FreeBSD 13.0 以降のみです。 FreeBSD で kTLS を使用して NGINX を有効にするを参照してください。

    • Linux カーネル バージョン 4.17 以降でビルドされた Linux ディストリビューション。ただし、可能な場合はバージョン 5.2 以降でビルドされたものを使用することをお勧めします。(kTLS サポートは実際にはバージョン 4.13 で使用できますが、OpenSSL 3.0.0 にはカーネル ヘッダー バージョン 4.17 以降が必要です。)

  • OpenSSL – バージョン 3.0.0 以降

  • NGINX – バージョン 1.21.4 以降 (メインライン)

    [編集者注NGINX Plus R27以降では、対象となる Linux ベースのオペレーティング システム バージョンで kTLS がサポートされます。NGINX Plus R26 以降では、対象となる FreeBSD バージョンで kTLS がサポートされます。 サポートされている OS の詳細については、NGINX Plusリリースページを参照してください。

オペレーティング システムのサポート

kTLSをサポートするOS

2021 年 11 月現在、 NGINX Open Source がサポートしているOS のうち、以下が kTLS と指定の暗号をサポートしています。 暗号サポートの詳細については、 「TLS プロトコルと暗号サポート」を参照してください。

  TLSv1.2 暗号 TLSv1.3
暗号スイート
TLS_CHACHA20_POLY1305_SHA256暗号 Linuxカーネルバージョン
Amazon Linux 2 * 5.10
CentOS8 ** 4.18
フリーBSD 13.x *** 該当なし
8 の 4.18
SLES 15 SP2 5.3
Ubuntu 20.04 LTS ❌​​ 5.4
ウブントゥ 21.04 5.11
ウブントゥ 21.10 5.13

  *カーネルバージョンは 4.14 ではなく 5.10 である必要があります。kTLSをサポートしない OSAmazon Linux 2 FAQ を参照してください。
**上流ソースであるRHEL 8からkTLSサポートステータスを継承
*** FreeBSDコミットログを参照

kTLSをサポートしないOS

以下の OS は、示されている理由により kTLS をサポートしていません。

  • Alpine Linux 3.11~3.14 – カーネルはCONFIG_TLS=nオプションを使用して構築されており、kTLS をモジュールまたはカーネルの一部として構築することが無効になっています。
  • Amazon Linux 2 – デフォルトの Amazon Linux 2 AMI の Linux カーネルバージョンは 4.14 です ( Amazon Linux 2 FAQを参照)。
  • 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 をサポートする OS は、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 をサポートする OSで指定されている一部の OS のみ)

OpenSSL でサポートされている TLS 暗号が NGINX バイナリで有効になっているかどうかを確認するには、NGINX をビルドしたディレクトリ (ホーム ディレクトリなど) でopenssl-3.0.0/.openssl/bin/openssl ciphersコマンドを実行します。

NGINX で kTLS を有効にする

はじめに述べたように、kTLS ではすべての暗号化と復号化がカーネル内で行われるため、NGINX のパフォーマンスが向上します。 データは、ネットワーク スタックに渡されて送信される前にカーネル空間で直接暗号化されるため、TLS ライブラリによって暗号化されるデータをユーザー空間にコピーし、その後カーネル空間に戻して送信する必要がなくなります。

NGINX を使用したカーネル TLS (kTLS) の図

カーネルに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 で kTLS を使用して NGINX を有効にする

FreeBSD 上の NGINX で kTLS サポートを有効にするには、Linux ディストリビューションの場合と同じ手順を使用できます。 ただし、 FreeBSD Ports Collectionsecurity/openssl-develポートで kTLS を使用した NGINX のビルドを活用するには、次の手順を実行することをお勧めします。 kTLS の概要を含む詳細については、FreeBSD Web サイトの「TLS Offload in the Kernel」を参照してください。

  1. 構成メニューで適切なオプションを選択して、kTLS サポート付きの OpenSSL 3.0 をビルドします。

    # cd /usr/ports/security/openssl-devel && config を実行 && インストールを実行
    
  2. openssl-devel をデフォルトの SSL ライブラリとして使用するように/etc/make.conf を変更します。

    # echo "DEFAULT_VERSIONS+=ssl=openssl-devel" >> /etc/make.conf
    
  3. NGINX をビルドします。

    # cd /usr/ports/www/nginx-devel && インストールする
    

Linux ディストリビューションで kTLS を使用して NGINX を構築する

現在の Linux ディストリビューションのほとんどには、OpenSSL バージョン 3.0.0 より前 (通常はバージョン 1.1) が含まれています。 したがって、OpenSSL 3.0.0 を使用してソースから NGINX をビルドする必要があります。

kTLS サポートを有効にするconfigureコマンドの 2 つの重要なオプションは次のとおりです。

  • --with-openssl=../openssl-3.0.0
  • --with-openssl-opt=ktls を有効にする

その他の構成オプションは、 nginx.orgで入手可能な公式NGINX バイナリ パッケージに含まれるモジュール用です。 代わりにカスタムのモジュール セットを指定することもできます。 現在の 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{}コンテキストにOptions KTLSパラメータを含むssl_conf_commandディレクティブを含めます。

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 [デバッグ] 274550#274550: *2 BIO_get_ktls_send(): 1 2021/11/10 16:02:49 [デバッグ] 274550#274550: *3 BIO_get_ktls_send(): 1 $ grep SSL_sendfile /var/log/nginx/error.log 2021/11/10 16:02:46 [デバッグ] 274550#274550: *2 SSL_sendfile: 1048576 2021/11/10 16:02:49 [デバッグ] 274550#274550: *3 SSL_sendfile: 1048576

注記: 特に実稼働環境では、これらのチェックを行った後、デバッグ モードを無効にすることをお勧めします。 デバッグ ログでは、書き込み操作の量が多いためパフォーマンスが低下します。また、デバッグ ログはサイズが大きくなり、ディスク パーティションの使用可能な領域がすぐに使い果たされる可能性があります。

kTLSによるパフォーマンスの向上

高負荷状態で静的ファイルとキャッシュされた応答を提供する場合、 SSL_sendfile() はユーザー空間 TLS と比較してスループットを最大 2 倍向上させることができますが、パフォーマンスの向上の程度はさまざまな要因 (ディスク パフォーマンス、システム負荷など) に大きく依存します。 ネットワーク カードが TLS オフロードをサポートしている場合は、CPU 使用率を削減することもできます。

パフォーマンスのテスト

セットアップのパフォーマンス向上を測定するには、次の手順に従って、単純な 1 スレッド テストを実行します。 以下に詳述するように、テスト結果では、特別な調整を行わなくてもパフォーマンスが最大 30% 近く向上することが示されています。

使用されるハードウェアとソフトウェア:

  • AWS t3.medium インスタンス:
    • 4GBのRAM
    • 20 GB 汎用 SSD
    • Intel® Xeon® Platinum 8259CL CPU @ 2.50GHz、2コア
  • FreeBSD 13.0 および Ubuntu 21.10
  • TLS_AES_256_GCM_SHA384暗号スイートを使用した TLSv1.3
  • NGINX 1.21.4 は、 「NGINX で kTLS を有効にする」の指定に従って構築および構成されています。

テストを実行するには:

  1. ディスク キャッシュに完全に収まる大きなファイルを作成します。

    #切り捨て -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/秒)です。 読みやすくするために出力は 2 行に分割されます。

kTLS なしの FreeBSD 13.0 のスループット:

    N 最小 最大 中央値 ...x 10 532225 573348 555616 ...

...      平均標準偏差 
... 555155.6 10239.137

kTLS を使用した FreeBSD 13.0 のスループット:

    N 最小 最大 中央値 ...x 10 629379 723164 717349 ...

...      平均標準偏差
... 708600.4 28304.766

kTLS なしの Ubuntu 21.10 のスループット:

    N 最小 最大 中央値 ...x 10 529199 705720 662354 ...

...      平均標準偏差
... 654321.6 48025.103

kTLS を使用した Ubuntu 21.10 のスループット:

    N 最小 最大 中央値 ...x 10 619105 760208 756278 ...

...      平均標準偏差
... 741848.3 43255.246

私たちのテストでは、kTLS は Ubuntu よりも FreeBSD でパフォーマンスを向上させました。 改善率は次のとおりです。

  マックス 中央値 平均
フリーBSD 13.0 18% 26% 29% 28%
ウブントゥ 21.10 16% 8% 14% 13%

まとめ

NGINX 1.21.4 では、 SSL_sendfile()を使用して静的ファイルとキャッシュされた応答を提供するときに kTLS のサポートが導入されています。 当社のテストでは、オペレーティング システムに応じてパフォーマンスが 8% ~ 29% 向上することが示されています。

kTLS と NGINX に関する皆様のご経験、特に他の OS でのテスト結果についてお聞かせください。 ぜひ下のコメント欄でシェアしてください。


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"