34.5. 高スループットのための TCP 接続のチューニング
Red Hat Enterprise Linux で TCP 関連の設定をチューニングして、スループットを向上させ、レイテンシーを短縮し、パケットロスなどの問題を防止します。
34.5.1. iperf3 を使用した TCP スループットのテスト
iperf3
ユーティリティーは、サーバーモードとクライアントモードを提供し、2 つのホスト間のネットワークスループットテストを実行します。
アプリケーションのスループットは、アプリケーションが使用するバッファーサイズなどの多くの要因に依存します。したがって、iperf3
などのテストユーティリティーで測定された結果は、実稼働ワークロード下のサーバー上のアプリケーションの結果とは大幅に異なる可能性があります。
前提条件
-
iperf3
パッケージはクライアントとサーバーの両方にインストールされている。 - どちらかのホスト上の他のサービスによって、テスト結果に大きな影響を与えるネットワークトラフィックが発生することはない。
- 速度が 40 Gbps 以上の接続の場合、ネットワークカードは Accelerated Receive Flow Steering (ARFS) をサポートし、この機能はインターフェイスで有効になっている。
手順
オプション: サーバーとクライアントの両方のネットワークインターフェイスコントローラー (NIC) の最大ネットワーク速度を表示します。
# ethtool enp1s0 | grep "Speed" Speed: 100000Mb/s
サーバー上では以下の設定になります。
firewalld
サービスでデフォルトのiperf3
TCP ポート 5201 を一時的に開きます。# firewall-cmd --add-port=5201/tcp
iperf3
をサーバーモードで起動します。# iperf3 --server
サービスは現在、受信クライアント接続を待機しています。
クライアントで以下を実行します。
スループットの測定を開始します。
# iperf3 --time 60 --zerocopy --client 192.0.2.1
--time <seconds>
: クライアントが送信を停止する時間を秒単位で定義します。このパラメーターを機能すると予想される値に設定し、後の測定で値を増やします。クライアントが送信パス上のデバイスまたはサーバーが処理できる速度よりも速い速度でパケットを送信すると、パケットがドロップされる可能性があります。
-
--zerocopy
:write()
システムコールを使用する代わりに、ゼロコピーメソッドを有効にします。このオプションは、ゼロコピー対応アプリケーションをシミュレートする場合、または単一ストリームで 40 Gbps 以上に達する場合にのみ必要です。 -
--client <server>
: クライアントモードを有効にし、iperf3
サーバーを実行するサーバーの IP アドレスまたは名前を設定します。
iperf3
がテストを完了するまで待ちます。サーバーとクライアントの両方で統計が毎秒表示され、最後に概要が表示されます。たとえば、以下はクライアントに表示される概要です。[ ID] Interval Transfer Bitrate Retr [ 5] 0.00-60.00 sec 101 GBytes 14.4 Gbits/sec 0 sender [ 5] 0.00-60.04 sec 101 GBytes 14.4 Gbits/sec receiver
この例では、平均ビットレートは 14.4 Gbps でした。
サーバー上では以下の設定になります。
-
Ctrl+C を押して
iperf3
サーバーを停止します。 firewalld
で TCP ポート 5201 を閉じます。# firewall-cmd --remove-port=5201/tcp
-
Ctrl+C を押して
関連情報
-
iperf3(1)
man ページ
34.5.2. システム全体の TCP ソケットバッファー設定
ソケットバッファーには、カーネルが受信したデータ、または送信する必要があるデータが一時的に保存されます。
- 読み取りソケットバッファーには、カーネルが受信したがアプリケーションがまだ読み取っていないパケットが保持されます。
- 書き込みソケットバッファーには、アプリケーションがバッファーに書き込んだものの、カーネルがまだ IP スタックとネットワークドライバーに渡していないパケットが保持されます。
TCP パケットが大きすぎてバッファーサイズを超えている場合、またはパケットの送受信速度が速すぎる場合、カーネルはデータがバッファーから削除されるまで、新しい受信 TCP パケットをドロップします。この場合、ソケットバッファーを増やすことでパケットロスを防ぐことができます。
net.ipv4.tcp_rmem
(読み取り) と net.ipv4.tcp_wmem
(書き込み) の両方のソケットバッファーカーネル設定には、次の 3 つの値が含まれます。
net.ipv4.tcp_rmem = 4096 131072 6291456 net.ipv4.tcp_wmem = 4096 16384 4194304
表示される値はバイト単位であり、Red Hat Enterprise Linux はそれらを次の方法で使用します。
- 最初の値は最小バッファーサイズです。新しいソケットのサイズを小さくすることはできません。
- 2 番目の値はデフォルトのバッファーサイズです。アプリケーションがバッファーサイズを設定しない場合、これがデフォルト値になります。
-
3 番目の値は、自動的にチューニングされるバッファーの最大サイズです。アプリケーションで
setsockopt()
関数をSO_SNDBUF
ソケットオプションとともに使用すると、この最大バッファーサイズが無効になります。
net.ipv4.tcp_rmem
および net.ipv4.tcp_wmem
パラメーターは、IPv4 プロトコルと IPv6 プロトコルの両方のソケットサイズを設定することに注意してください。
34.5.3. システム全体の TCP ソケットバッファーの増加
システム全体の TCP ソケットバッファーには、カーネルが受信したデータ、または送信する必要があるデータが一時的に保存されます。net.ipv4.tcp_rmem
(読み取り) と net.ipv4.tcp_wmem
(書き込み) の両方のソケットバッファーカーネル設定には、それぞれ最小値、デフォルト値、および最大値の 3 つの設定が含まれています。
バッファーサイズを大きすぎる設定にすると、メモリーが無駄に消費されます。各ソケットはアプリケーションが要求するサイズに設定でき、カーネルはこの値を 2 倍にします。たとえば、アプリケーションが 256 KiB のソケットバッファーサイズを要求し、100 万個のソケットを開く場合、システムは潜在的なソケットバッファースペースとしてのみ最大 512 GB RAM (512 KiB x 100 万) を使用できます。
さらに、最大バッファーサイズの値が大きすぎると、レイテンシーが長くなる可能性があります。
前提条件
- かなりの割合で TCP パケットがドロップされました。
手順
接続の遅延を決定します。たとえば、クライアントからサーバーに ping を実行して、平均ラウンドトリップ時間 (RTT) を測定します。
# ping -c 10 server.example.com ... --- server.example.com ping statistics --- 10 packets transmitted, 10 received, 0% packet loss, time 9014ms rtt min/avg/max/mdev = 117.208/117.056/119.333/0.616 ms
この例では、レイテンシーは 117 ミリ秒です。
次の式を使用して、チューニングするトラフィックの帯域幅遅延積 (BDP) を計算します。
connection speed in bytes * latency in ms = BDP in bytes
たとえば、レイテンシーが 117 ミリ秒の 10 Gbps 接続の BDP を計算するには、次のようにします。
(10 * 1000 * 1000 * 1000 / 8) * 117 = 10683760 bytes
/etc/sysctl.d/10-tcp-socket-buffers.conf
ファイルを作成し、要件に基づいて、最大読み取りバッファーサイズまたは書き込みバッファーサイズ、またはその両方を設定します。net.ipv4.tcp_rmem = 4096 262144 21367520 net.ipv4.tcp_wmem = 4096 24576 21367520
値をバイト単位で指定します。環境に最適化された値を特定するには、以下の大体の目安を参考にしてください。
-
デフォルトのバッファーサイズ (2 番目の値): この値をわずかに増やすか、最大でも
524288
(512 KiB) に設定します。デフォルトのバッファーサイズが大きすぎると、バッファーの崩壊が発生し、その結果、遅延が急増する可能性があります。 - 最大バッファーサイズ (3 番目の値): 多くの場合、BDP の 2 倍から 3 倍の値で十分です。
-
デフォルトのバッファーサイズ (2 番目の値): この値をわずかに増やすか、最大でも
/etc/sysctl.d/10-tcp-socket-buffers.conf
ファイルから設定をロードします。# sysctl -p /etc/sysctl.d/10-tcp-socket-buffers.conf
より大きなソケットバッファーサイズを使用するようにアプリケーションを設定します。
net.ipv4.tcp_rmem
およびnet.ipv4.tcp_wmem
パラメーターの 3 番目の値は、アプリケーションのsetsockopt()
関数が要求できる最大バッファーサイズを定義します。詳細は、アプリケーションのプログラミング言語のドキュメントを参照してください。アプリケーションの開発者ではない場合は、開発者にお問い合わせください。
net.ipv4.tcp_rmem
またはnet.ipv4.tcp_wmem
パラメーターの 2 番目の値を変更した場合は、新しい TCP バッファーサイズを使用するようにアプリケーションを再起動します。3 番目の値のみを変更した場合は、自動チューニングによってこれらの設定が動的に適用されるため、アプリケーションを再起動する必要はありません。
検証
- オプション: iperf3 を使用して TCP スループットをテストします。
パケットドロップが発生したときに使用したのと同じ方法を使用して、パケットドロップ統計を監視します。
パケットドロップが依然として発生するが、レートが低い場合は、バッファーサイズをさらに増やします。
関連情報
- What are the implications of changing socket buffer sizes? (Red Hat ナレッジベース)
-
システム上の
tcp(7)
およびsocket(7)
man ページ
34.5.4. TCP ウィンドウのスケーリング
Red Hat Enterprise Linux でデフォルトで有効になっている TCP ウィンドウスケーリング機能は、スループットを大幅に向上させる TCP プロトコルの拡張機能です。
たとえば、ラウンドトリップ時間 (RTT) が 1.5 ミリ秒の 1 Gbps 接続の場合、次のようになります。
- TCP ウィンドウスケーリングを有効にすると、約 630 Mbps が現実的になります。
- TCP ウィンドウスケーリングを無効にすると、スループットは 380 Mbps に低下します。
TCP が提供する機能の 1 つはフロー制御です。フロー制御を使用すると、送信者は受信者が受信可能な量のデータを送信できますが、それ以上のデータは送信できません。これを達成するために、受信者は、送信者が送信できるデータの量である window
値をアドバタイズします。
TCP は当初、最大 64 KiB のウィンドウサイズをサポートしていましたが、帯域幅遅延積 (BDP) が高い場合、送信者が一度に 64 KiB を超えるサイズを送信できないため、この値が制限となります。高速接続では、一度に 64 KiB をはるかに超えるデータを転送できます。たとえば、システム間の遅延が 1 ms の 10 Gbps リンクでは、一度に 1 MiB を超えるデータが転送される可能性があります。ホストが 64 KiB のみを送信し、他のホストがその 64 KiB を受信するまで一時停止する場合、非効率的になります。
このボトルネックを解消するために、TCP ウィンドウスケーリング拡張機能を使用すると、TCP ウィンドウ値を左算術シフトしてウィンドウサイズを 64 KiB を超えて増やすことができます。たとえば、最大ウィンドウ値 65535
は左に 7 桁シフトし、ウィンドウサイズは 8 MiB 近くになります。これにより、一度により多くのデータを転送できるようになります。
TCP ウィンドウスケーリングは、すべての TCP 接続を開く 3 ウェイ TCP ハンドシェイク中にネゴシエートされます。この機能が動作するには、送信者と受信者の両方が TCP ウィンドウスケーリングをサポートしている必要があります。参加者の一方または両方がハンドシェイクでウィンドウスケーリング機能をアドバタイズしない場合、接続は元の 16 ビット TCP ウィンドウサイズの使用に戻ります。
デフォルトでは、TCP ウィンドウスケーリングは Red Hat Enterprise Linux で有効になっています。
# sysctl net.ipv4.tcp_window_scaling
net.ipv4.tcp_window_scaling = 1
サーバー上で TCP ウィンドウスケーリングが無効 (0
) になっている場合は、設定した際と同じ方法で設定を元に戻します。
34.5.5. TCP SACK がパケットドロップ率を下げる仕組み
Red Hat Enterprise Linux (RHEL) でデフォルトで有効になっている TCP Selective Acknowledgment (TCP SACK) 機能は、TCP プロトコルの拡張機能であり、TCP 接続の効率を高めます。
TCP 送信では、受信者は受信するパケットごとに ACK パケットを送信者に送信します。たとえば、クライアントは TCP パケット 1 - 10 をサーバーに送信しますが、パケット番号 5 と 6 が失われます。TCP SACK がないと、サーバーはパケット 7 - 10 をドロップし、クライアントは損失点からすべてのパケットを再送信する必要があり、非効率的です。両方のホストで TCP SACK が有効になっている場合、クライアントは失われたパケット 5 と 6 のみを再送信する必要があります。
TCP SACK を無効にするとパフォーマンスが低下し、TCP 接続の受信側でのパケットドロップ率が高くなります。
デフォルトでは、RHEL では TCP SACK が有効になっています。確認するには、以下を実行します。
# sysctl net.ipv4.tcp_sack
1
サーバー上で TCP SACK が無効 (0
) になっている場合は、設定した際と同じ方法で設定を元に戻します。