LinuxNETパフォーマンス最適化実践研究ノート

以下のコンテンツはオタクコースのものです。役立つ場合は、詳細コースのポスターをご覧ください。
画像名

NETパフォーマンス

NETパフォーマンス関連の知識

1.基礎知識

次に、カーネルプロトコルスタックはバッファからネットワークフレームを取り出し、ネットワークプロトコルスタックを介してネットワークフレームを下から上にレイヤーごとに処理します。といった、

  1. リンク層でメッセージの正当性を確認して、上位層プロトコルのタイプ(IPv4やIPv6など)を確認し、フレームヘッダーとフレームテールを削除してから、ネットワーク層に渡します。
  2. ネットワーク層はIPヘッダーを取り出し、処理または転送のために上位層に渡されるかどうかなど、ネットワークパケットの次の方向を判断します。ネットワーク層は、パケットがローカルマシンに送信されることを確認すると、上位層プロトコルのタイプ(TCPやUDPなど)を取り出し、IPヘッダーを削除して、処理のためにトランスポート層に渡します。 。
  3. トランスポート層は、TCPヘッダーまたはUDPヘッダーを取り出した後、<送信元IP、送信元ポート、宛先IP、宛先ポート>の4倍を識別子として、対応するソケットを見つけ、そのデータをソケットの受信バッファーにコピーします。 。
  4. 最後に、アプリケーションはSocketインターフェースを使用して、新しく受信したデータを読み取ることができます。

2.NICインジケーター

第4に、ネットワークによって送受信されるバイト数、パケット数、エラー数、およびパケット損失状態、特にTX部分とRX部分のエラー、ドロップ、オーバーラン、キャリア、および衝突が0でない場合、通常はネットワークI / Oの質問。その中で:

  • エラーは、チェックエラー、フレーム同期エラーなどのエラーのあるパケットの数を表します。
  • ドロップされたパケットは、ドロップされたパケットの数を示します。つまり、パケットはリングバッファを受信しましたが、メモリ不足などの理由でパケットがドロップされました。
  • オーバーランとは、オーバーランデータパケットの数を意味します。つまり、ネットワークI / O速度が速すぎて、リングバッファ内のデータパケットを処理するには遅すぎ(キューがいっぱい)、パケット損失が発生します。
  • キャリアは、デュプレックスモードでの不一致、物理ケーブルの問題など、キャリアエラーのあるパケットの数を示します。
  • 衝突は、衝突パケットの数を表します。

3. C10K、C1000K問題の最適化

IOモデルの最適化
  • 水平トリガー:ファイル記述子がI / Oノンブロッキングを実行できる限り、通知がトリガーされます。つまり、アプリケーションはいつでもファイル記述子のステータスを確認し、そのステータスに基づいてI / O操作を実行できます。
  • エッジトリガー:ファイル記述子のステータスが変更された場合(つまり、I / O要求に達した場合)にのみ、通知が送信されます。このとき、アプリケーションは可能な限り多くのI / Oを実行する必要があり、読み取りまたは書き込みを続行できなくなるまで停止できます。I / Oが完了していない場合、または何らかの理由で処理する時間がない場合、通知は失われます。
  1. 1つ目は、非ブロッキングI / Oと、選択やポーリングなどのレベルトリガー通知を使用することです。
  2. 2つ目は、非ブロッキングI / Oおよびepollなどのエッジトリガー通知を使用することです。
  3. 3つ目は、非同期I / O(非同期I / O、AIOと呼ばれる)を使用することです。
作業モデルの最適化

1.最初のタイプであるメインプロセス+複数のワーカー子プロセス。これも最も一般的に使用されるモデルです。
ここで、accept()とepoll_wait()の呼び出しには、まだ衝撃的な問題があることに注意してください。つまり、ネットワークI / Oイベントが発生すると、複数のプロセスが同時にウェイクアップされますが、実際には1つのプロセスのみがこのイベントに応答し、他のウェイクアップされたプロセスは再びスリープ状態になります。その中で、accept()のショックグループの問題はLinux 2.6で解決されました。そして、epollの問題は、EPOLLEXCLUSIVEによって解決されたのはLinux4.5だけでした。ショックグループの問題を回避するために、Nginxは各ワーカープロセスにグローバルロック(accept_mutex)を追加します。これらのワーカープロセスは最初にロックを競合する必要があり、ロックを競合するプロセスのみがepollに追加され、1つのワーカー子プロセスのみがウェイクアップされるようにします。
2. 2つ目は、同じポートをリッスンするマルチプロセスモデルです。

4.システムのネットワークパフォーマンスを評価する方法

  • アプリケーション層では、wrk、Jmeterなどを使用して、ユーザーの負荷をシミュレートし、1秒あたりのリクエスト数、処理遅延、アプリケーションのエラー数などをテストできます。
  • トランスポート層では、iperfなどのツールを使用してTCPスループットをテストできます。
  • さらに、Linuxカーネルに付属のpktgenを使用して、サーバーのPPSをテストすることもできます。

5.DDosを最適化する方法

  1. 送信元IPに応じて、同時接続の数とSYNの頻度を制限します
# 限制syn并发数为每秒1次
$ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT
# 限制单个IP在60秒新建立的连接数为10
$ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT
  1. ハーフオープン接続の数を増やします。デフォルトは256です。
$ $ sysctl -w net.ipv4.tcp_max_syn_backlog=1024
net.ipv4.tcp_max_syn_backlog = 1024
  1. 各SYN_RECVを接続するときに失敗した場合、カーネルは自動的に再試行し、デフォルトの再試行回数は5回です。次のコマンドを実行して、1回に減らすことができます。
    $ sysctl -w net.ipv4.tcp_synack_retries = 1
  2. SYNクッキーをオンにする
$ sysctl -w net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syncookies = 1

6.クライアントTCP_QUICKACKがオフになっている+サーバーがオンになっているNagle、これにより遅延が増加します

ここに画像の説明を挿入

7.NATを最適化する方法

主に、接続追跡テーブルのデフォルトパラメータを調整します。重要な指標:

  • net.netfilter.nf_conntrack_countは、現在の接続追跡番号を意味します。
  • net.netfilter.nf_conntrack_maxは、接続追跡の最大数を示します。
  • net.netfilter.nf_conntrack_bucketsは、接続追跡テーブルのサイズを示します。

接続追跡テーブルが占めるメモリサイズ:

# 连接跟踪对象大小为376,链表项大小为16
nf_conntrack_max*连接跟踪对象大小+nf_conntrack_buckets*链表项大小 
= 1000*376+65536*16 B
= 1.4 MB

参考資料:
https //mp.weixin.qq.com/s/VYBs8iqf0HsNg9WAxktzYQ

8.ネットワークパフォーマンスの最適化に関する一般的なアイデア

応用

  • epoll + aioなどを使用します。
  • 短い接続の代わりに長い接続を使用すると、TCP接続の確立のコストを大幅に削減できます。1秒あたりのリクエスト数が多い場合、その影響は非常に明白です。
  • メモリやその他の方法を使用して、頻繁に変更されないデータをキャッシュすると、ネットワークI / Oの数を減らし、アプリケーションの応答速度を上げることができます。
  • プロトコルバッファなどのシリアル化方法を使用してネットワークI / Oのデータ量を圧縮すると、アプリケーションのスループットを向上させることができます。
  • DNSキャッシング、プリフェッチ、HTTPDNS、およびその他の方法を使用して、DNS解決の遅延を減らし、ネットワークI / Oの全体的な速度を向上させます。

ソケット

したがって、ネットワークのスループットを向上させるには、通常、これらのバッファのサイズを調整する必要があります。といった:

  • 各ソケットのバッファサイズを増やしますnet.core.optmem_max;
  • ソケットの受信バッファーサイズnet.core.rmem_maxを増やし、送信バッファーサイズnet.core.wmem_maxを増やします。
  • TCP受信バッファーサイズnet.ipv4.tcp_rmemを増やし、送信バッファーサイズnet.ipv4.tcp_wmemを増やします。

ここに画像の説明を挿入
たとえば、送信バッファサイズの場合、理想的な値はスループット*遅延であるため、最大のネットワーク使用率を達成できます。
さらに、ソケットインターフェイスは、ネットワーク接続の動作を変更するためのいくつかの構成オプションも提供します。

  • TCP接続にTCP_NODELAYを設定した後、Nagleアルゴリズムを無効にすることができます。
  • TCP接続用にTCP_CORKを開いた後、送信する前に小さなパケットを大きなパケットに集約できます(小さなパケットの送信をブロックすることに注意してください)。
  • SO_SNDBUFとSO_RCVBUFを使用して、ソケット送信バッファーと受信バッファーのサイズをそれぞれ調整できます。

トランスポート層

最初のカテゴリでは、リクエストの数が比較的多いシナリオで、TIME_WAIT状態の接続が多数表示される場合があります。これにより、大量のメモリとポートリソースが消費されます。このとき、以下の対策など、TIME_WAIT状態に関連するカーネルオプションを最適化することができます。

  • TIME_WAIT状態の接続net.ipv4.tcp_max_tw_bucketsの数を増やし、接続追跡テーブルnet.netfilter.nf_conntrack_maxのサイズを増やします。
  • net.ipv4.tcp_fin_timeoutとnet.netfilter.nf_conntrack_tcp_timeout_time_waitを減らして、システムが占有しているリソースをできるだけ早く解放できるようにします。
  • ポートの再利用net.ipv4.tcp_tw_reuseを有効にします。このようにして、TIME_WAIT状態が占めるポートは、新しく作成された接続でも使用できます。
  • ローカルポート範囲net.ipv4.ip_local_port_rangeを増やします。このようにして、より多くの接続をサポートでき、全体的な同時実行性を向上させることができます。
  • 最大ファイル記述子の数を増やします。fs.nr_openとfs.file-maxを使用して、プロセスとシステムのファイル記述子の最大数をそれぞれ増やすか、アプリケーションのsystemd構成ファイルでLimitNOFILEを構成して、アプリケーションのファイル記述子の最大数を設定できます。

2番目のカテゴリは、SYN FLOODなどのTCPプロトコル特性を使用した攻撃によって引き起こされるパフォーマンスの問題を軽減するために、次の対策を講じるなど、SYN状態に関連するカーネルオプションの最適化を検討できます。

3番目のカテゴリである長い接続シナリオでは、通常、キープアライブを使用してTCP接続のステータスを検出します。これにより、ピア接続が切断された後、自動的にリサイクルできます。ただし、システムのデフォルトのキープアライブ検出間隔と再試行回数は、通常、アプリケーションのパフォーマンス要件を満たすことができません。したがって、現時点では、次のようなキープアライブに関連するカーネルオプションを最適化する必要があります。

  • 最後のデータパケットとキープアライブ検出パケットの間隔を短くしますnet.ipv4.tcp_keepalive_time;
  • キープアライブ検出パケットを送信する間隔時間を短縮しますnet.ipv4.tcp_keepalive_intvl;
  • キープアライブプローブが失敗した後、アプリケーションに通知されるまで、net.ipv4.tcp_keepalive_probesの再試行回数を減らします。

ここに画像の説明を挿入
UDPは、データグラム指向のネットワークプロトコルを提供します。ネットワーク接続を必要とせず、信頼性の保証も提供しません。したがって、UDPの最適化はTCPよりもはるかに簡単です。ここでは、いくつかの一般的な最適化スキームについても要約しました。

  • 前のソケットの部分で述べたように、ソケットバッファサイズとUDPバッファ範囲を増やします。
  • 前のTCPセクションで説明したように、ローカルポート番号の範囲を増やします。
  • MTUサイズに応じて、UDPデータパケットのサイズを調整して、断片化を減らすか回避します。

リンク層

ネットワークカードがパケットを受信した後に呼び出される割り込みハンドラ(特にソフト割り込み)のため、多くのCPUを消費する必要があります。したがって、これらの割り込みハンドラを異なるCPUで実行するようにスケジュールすると、ネットワークスループットを大幅に向上させることができます。これは通常、次の2つの方法で実行できます。といった、

  • ネットワークカードのハード割り込みに対してCPUアフィニティ(smp_affinity)を設定するか、irqbalanceサービスを有効にすることができます。
  • 別の例として、RPS(パケットステアリングの受信)とRFS(フローステアリングの受信)を有効にして、アプリケーションとソフト割り込み処理を同じCPUにスケジュールできるため、CPUキャッシュのヒット率を高め、ネットワーク遅延を減らすことができます。

さらに、現在のネットワークカードには非常に豊富な機能があります。カーネル内のソフトウェアによって元々処理されていた機能は、ネットワークカードにオフロードして、ハードウェアによって実行できます。

  • TSO(TCPセグメンテーションオフロード)およびUFO(UDPフラグメンテーションオフロード):TCP / UDPプロトコルで直接大きなパケットを送信します。TCPパケットセグメンテーション(MSSセグメンテーションに準拠)およびUDPセグメンテーション(MTUセグメンテーションに準拠)機能。ネットワークカード。
  • GSO(Generic Segmentation Offload):ネットワークカードがTSO / UFOをサポートしていない場合、TCP / UDPパケットのセグメンテーションは、実行前にネットワークカードに入るまで遅延されます。このようにして、CPUの消費を削減できるだけでなく、パケット損失が発生したときにフラグメント化されたパケットのみを再送信できます。
  • LRO(ラージレシーブオフロード):TCPセグメント化されたパケットを受信すると、ネットワークカードはそれらをアセンブルしてマージし、処理のために上位ネットワークに送信します。ただし、IP転送が必要な場合、LROをオンにできないことに注意してください。これは、複数のパケットのヘッダー情報に一貫性がない場合、LROのマージによってネットワークパケット検証エラーが発生するためです。
  • GRO(Generic Receive Offload):GROはLROの欠陥を修正し、より用途が広く、TCPとUDPの両方をサポートします。
  • RSS(Receive Side Scaling):マルチキュー受信とも呼ばれ、ハードウェア内の複数の受信キューに基づいてネットワーク受信プロセスを割り当て、複数のCPUが受信したネットワークパケットを処理できるようにします。
  • VXLANのアンインストール:つまり、ネットワークカードにVXLANパッケージ機能を完了させます。

?? tcpに関して、タイムスタンプを開くことに関する検証パラメータがあります:tcp_timestamps。nat環境がある場合は開かないでください。cat/ proc / sys / net / ipv4 / tcp_timestampsを開くかどうかを確認できます。

ネットワーク上の一般的なコマンド

1.ソケット情報ssまたはnetstat

# head -n 3 表示只显示前面3行
# -l 表示只显示监听套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ netstat -nlp | head -n 3
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 840/systemd-resolve

# -l 表示只显示监听套接字
# -t 表示只显示 TCP 套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ ss -ltnp | head -n 3
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=840,fd=13))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1459,fd=3))

その中で、受信キュー(Recv-Q)と送信キュー(Send-Q)には特別な注意が必要であり、通常は0である必要があります。それらが0でないことがわかった場合、それはネットワークパケットの蓄積があることを意味します。もちろん、ソケットの状態が異なれば、その意味も異なることに注意してください。
ソケットが接続状態(確立済み)の場合、

  • Recv-Qは、アプリケーションによって削除されなかったソケットバッファー内のバイト数(つまり、受信キューの長さ)を表します。
  • また、Send-Qは、リモートホストによって確認されていないバイト数(つまり、送信キューの長さ)を表します。

ソケットがリスニング状態(リスニング)の場合、

  • Recv-Qは、完全に接続されたキューの長さを表します。
  • また、Send-Qは、完全に接続されたキューの最大長を表します。

いわゆる完全接続とは、サーバーがクライアントからACKを受信し、TCPスリーウェイハンドシェイクを完了してから、接続を完全接続キューに移動することを意味します。これらの完全な接続のソケットは、サーバーが実際にクライアントの要求を処理する前に、accept()システムコールによって削除される必要があります。完全に接続されたキューに対応して、半接続されたキューもあります。いわゆるハーフ接続とは、TCPスリーウェイハンドシェイクが完了していない接続を指し、接続は途中でしか進行していません。サーバーはクライアントからSYNパケットを受信した後、接続を半接続キューに入れ、SYN + ACKパケットをクライアントに送信します。

2.プロトコルスタック情報ss-sまたはnetstat-s

3.ネットワークスループットとPPS(sar)

# 数字1表示每隔1秒输出一组数据
$ sar -n DEV 1
Linux 4.15.0-1035-azure (ubuntu) 01/06/19 _x86_64_ (2 CPU)
13:21:40 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
13:21:41 eth0 18.00 20.00 5.79 4.25 0.00 0.00 0.00 0.00
13:21:41 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
13:21:41 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

ここには多くの指標が出力されていますが、その意味を簡単に説明します。

  • rxpck / sとtxpck / sは送受信されたPPSであり、単位はパケット/秒です。
  • rxkB / sとtxkB / sはそれぞれ受信と送信のスループットであり、単位はKB /秒です。
  • rxcmp / sおよびtxcmp / sは、送受信された圧縮データパケットの数であり、単位はパケット/秒です。
  • %ifutilは、ネットワークインターフェイスの使用率です。つまり、半二重モードでは(rxkB / s + txkB / s)/帯域幅、全二重モードではmax(rxkB / s、txkB / s)/帯域幅です。

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/zimu312500/article/details/114239806