ネットワークサブシステムは複雑な構造であるため、チューニングはシステムの用途に大きく依存するほか、ソフトウエアクライアントやハードウエアコンポーネント (スイッチ、ルータ、ゲートウエイ) などの外部要素にも依存します。 Linux カーネルでは、オーバーヘッドを低くしたり高いスループットを提供したりする代わりに、信頼性と遅延の少なさを主眼に置いてします。また、その他の設定はセキュリティを低下させますが、性能を改善することができるようになっています。
昨今のネットワーク通信の多くは TCP/IP プロトコルをベースにして行われていて、実際の処理はソケットインターフェイスを使用するのが一般的です。 TCP/IP に関する詳細については、 第13章 「ネットワークの基礎」 をお読みください。 Linux カーネルでは、ソケットインターフェイスを介して、バッファ内に受信したデータや送信すべきデータを蓄積し、必要な送受信を行います。これらのカーネルのソケットバッファについては、チューニングによる調整を行うことができます。
カーネルバージョン 2.6.17 もしくはそれ以降のバージョンでは、最大バッファサイズ 4 MB で自動チューニングを行うようになっています。この仕組みにより、手作業でチューニングを行ったとしても、通常はネットワーク性能を改善できないことを意味しています。また下記の変数についても、通常は変更せずにそのままにしておくことが最適です。変更を行う場合は、チューニング作業による影響をよく確認しておくことをお勧めします。
また、古いバージョンのカーネルから更新した場合は、手作業で行っていた TCP のチューニングを削除し、自動チューニングに任せることをお勧めします。
/proc
ファイルシステム内にある特殊なファイルを使用することで、カーネルのソケットバッファのサイズや動作を変更することができます。 /proc
ファイルシステムに関する一般的な情報については、 2.6項 「/proc
ファイルシステム」 をお読みください。このうち、ネットワーク関連のファイルは下記の中に含まれています:
/proc/sys/net/core /proc/sys/net/ipv4 /proc/sys/net/ipv6
一般的な net
関係の変数は、カーネルのドキュメンテーション ( linux/Documentation/sysctl/net.txt
) 内に説明があります。また、 ipv4
以下の変数は、 linux/Documentation/networking/ip-sysctl.txt
と linux/Documentation/networking/ipvs-sysctl.txt
内に説明があります。
/proc
ファイルシステム内では、たとえば全てのプロトコルに対する最大ソケット受信バッファサイズや最大ソケット送信バッファサイズを設定することができます。この場合、これらを TCP プロトコルにのみ適用することができる (ipv4
内) ほか、全てのプロトコルに対して上書きで設定することのできるもの (core
内) もあります。
/proc/sys/net/ipv4/tcp_moderate_rcvbuf
/proc/sys/net/ipv4/tcp_moderate_rcvbuf
を 1
に設定すると、自動チューニング機能が有効化され、バッファサイズが動的に調整されるようになります。
/proc/sys/net/ipv4/tcp_rmem
3 種類の値を設定する変数で、 1 接続あたりのメモリ内受信バッファの最小値/初期値/最大値をそれぞれ設定します。ここでは TCP のウインドウサイズだけでなく、実際のメモリ使用量を調整することにもなります。
/proc/sys/net/ipv4/tcp_wmem
tcp_rmem
と同じような変数ですが、こちらは 1 接続あたりのメモリ内の送信バッファを設定します。
/proc/sys/net/core/rmem_max
アプリケーション側から要求することのできる、最大の受信バッファサイズを制限するための変数です。
/proc/sys/net/core/wmem_max
アプリケーション側から要求することのできる、最大の送信バッファサイズを制限するための変数です。
/proc
を利用することで、不要な TCP 機能を無効化することができます (既定では全ての TCP 機能が有効化されています) 。たとえば下記のようなファイルがあります:
/proc/sys/net/ipv4/tcp_timestamps
TCP のタイムスタンプ機能は、 RFC1323 で規定されているものです。
/proc/sys/net/ipv4/tcp_window_scaling
TCP のウインドウスケーリングについても、 RFC1323 で規定されています。
/proc/sys/net/ipv4/tcp_sack
選択的確認応答 (SACK) の設定を行います。
sysctl
コマンドを使用することで、 /proc
ファイルシステム内の変数を読み込んだり書き込んだりすることができます。 sysctl
コマンドは /etc/sysctl.conf
ファイルから設定を読み込む仕組みであり、これによってシステムを再起動しても設定を再適用することができるため、 cat
(読み込み) や echo
(書き込み) を利用して /proc
ファイルシステムにアクセスするよりは、 sysctl
コマンドを使用することをお勧めします。 sysctl
コマンドでの変数の読み込みや書き込みは簡単で、たとえば下記のように入力して実行することで、 TCP 関連の変数を全て表示することができます:
>
sudo
sysctl -a | grep tcp
ネットワーク変数のチューニングによって、 CPU やメモリなどの他のシステムリソースに影響がある場合があります。
ネットワークのチューニングを行う前に、あらかじめネットワーク内にボトルネックが存在していないかを確認し、ネットワークのトラフィックパターンについても調べておくことが重要です。これらを実施するために、いくつかのツールが提供されています。
ネットワークトラフィックを分析するには、 netstat
, tcpdump
, wireshark
などのツールをお使いいただくことができます。 Wireshark はネットワークトラフィックアナライザです。
Linux におけるファイアウオール機能やマスカレード機能は、 netfilter と呼ばれるカーネルモジュールが提供する機能です。このモジュールは、ルールベースのフレームワークら介して、高度に設定することができます。あるパケットが指定したルールに該当した場合、 netfilter ではパケットを受け付けるか拒否するかを選択することができるほか、特殊なアクション ( 「ターゲット」 と呼びます) を指定して、アドレス変換などの処理を行うこともできます。
netfilter には多数の設定項目が存在しています。そのため、ルールを多く設定すればするほど、パケットの処理にも時間がかかることになります。また、高度な接続追跡機能を使用すると、より CPU 負荷がかかることになりますので、ネットワーク全体の処理の低下にも繋がります。
カーネル側のキューがいっぱいになると、新しく届いたパケットが廃棄されるようになります。これにより、既存の接続が正しく動作しなくなってしまいます。 '故障時開' (fail-open) の機能を使用すると、ネットワークトラフィックが多すぎる場合、一時的にパケットの調査を無効化して接続を維持することができるようになります。詳しくは https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/ (英語) をお読みください。
詳しくは netfilter/iptables プロジェクトの Web ページ https://www.netfilter.org (英語) をご覧ください。
新しいネットワークインターフェイスを使用している場合、多数のパケットを取り扱うことになることから、ホスト側が性能面のボトルネックとなる場合があります。これらのパケットを問題なく扱うことができるようにするため、システム側では複数の CPU コアに分散させて処理を行わなければなりません。
新しいネットワークインターフェイスの場合、ハードウエア側に実装された複数の送受信キューを使用することで、複数の CPU コアに処理を分散させることができます。ハードウエア側にそのような仕組みが用意されておらず、単一のキューしか用意されていない場合、ドライバは単一の直列化されたストリームを介して、全ての到着パケットを処理しなければならなくなります。この問題に対応するには、オペレーティングシステムがストリームを 「並列化」 して、複数の CPU に処理を分散させなければなりません。このような分散処理の仕組みが Receive Packet Steering (RPS) です。 RPS は仮想環境でも使用することができます。
RPS は各データストリームに対して、 IP アドレスとポート番号をベースにしたユニークなハッシュを作成します。このハッシュを使用することで、同じデータストリームを同じ CPU で処理できるようにし、性能を向上させることができるようになっています。
RPS はネットワークデバイスの受信キューおよびインターフェイスごとに設定することができます。設定のファイル名は、下記のようになっています:
/sys/class/net/デバイス名/queues/受信キュー名/rps_cpus
デバイス名 にはネットワークデバイスのデバイス名が入ります。たとえば eth0
, eth1
のような名前になります。また、 受信キュー名 には、受信キューの名前が入ります。たとえば rx-0
, rx-1
のような名前になります。
ネットワークインターフェイスが単一の受信キューしか提供していない場合は、 rx-0
のみが存在することになります。複数の受信キューに対応している場合は、 rx- N のディレクトリが複数存在していることになります。
下記の設定ファイルには、 CPU をビットマップ形式で指定します。既定では全てのビットが 0
になっています。この設定では、 RPS が無効化されているため、割り込みを処理した CPU がパケットキューの処理をも行うことになります。
RPS を有効化し、特定の CPU がインターフェイスの受信キューを処理するように設定するには、その CPU のビットを 1
に設定します。たとえば CPU 0 から 3 までを eth0 の最初の受信キューの処理に使用したい場合は、ビット 0 から 3 までを 1 にした値、つまり 2 進数で 00001111
を設定します。なお、実際の設定作業は、 16 進数で指定します。この場合は F
を設定することになります。このことから、設定作業は下記のようになります:
>
sudo
echo "f" > /sys/class/net/eth0/queues/rx-0/rps_cpus
CPU 8 から 15 までを有効化したい場合は、下記のように設定します:
1111 1111 0000 0000 (2 進数) 15 15 0 0 (10 進数) F F 0 0 (16 進数)
生成できた 16 進数値は ff00
になりますので、下記のコマンドで設定します:
>
sudo
echo "ff00" > /sys/class/net/eth0/queues/rx-0/rps_cpus
NUMA マシンの場合、 RPS を設定してインターフェイスの受信キュー割り込みの処理と同じ NUMA ノードの CPU で処理を行うようにすると、最適な性能を発揮できるようになります。
非 NUMA マシンの場合、全ての CPU を使用することができます。割り込みの割合が大きい場合、ネットワークインターフェスを処理している CPU を除外することで、性能を発揮できるようになります。ネットワークインターフェイスを処理している CPU は、 /proc/interrupts
ファイルから判断することができます。たとえば下記のようになります:
>
sudo
cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 ... 51: 113915241 0 0 0 Phys-fasteoi eth0 ...
この場合、 eth0
の割り込みを処理しているのは CPU 0
になります。これは、 CPU0
のみが 0 より大きくなっているためです。
x86 および AMD64/Intel 64 プラットフォームの場合、 irqbalance
を使用することで、ハードウエア割り込みを CPU 間に分散させることができます。詳しくは man 1 irqbalance
をお読みください。