4

低遅延ネットワークについて基本的なグーグル検索を行った結果、プログラマーとシステム設計者が低遅延ネットワークに着手する際に考慮すべき事項の次のリストを思いつきました。

  1. ハードウェア、システム、およびプロトコルの設計は、一緒に検討する必要があります

  2. TCP の代わりに UDP を使用してプロトコルを開発し、単純な ack-nak を実装し、アプリケーション レベルでロジックを再送信します。

  3. ネットワークからデータを消費してパケット化するプロセスまたはスレッドのコンテキスト スイッチの数を (できればゼロに) 減らします。

  4. OS に最適なセレクターを使用する (select、kqueue、epoll など)

  5. 大量のオンボード バッファ (fifo) を備えた高品質の NIC とスイッチを使用する

  6. 特にダウンストリームとアップストリームのデータ フローに複数の NIC を使用する

  7. 他のデバイスまたはソフトウェアによって生成される IRQ の数を減らします (つまり、不要な場合は削除します)。

  8. ミューテックスと条件の使用を減らします。代わりに、可能であればロックフリー プログラミング手法を使用してください。アーキテクチャの CAS 機能を利用します。(ロックフリーコンテナ)

  9. マルチスレッド設計よりもシングルスレッド設計を検討してください - コンテキストスイッチは非常に高価です。

  10. アーキテクチャのキャッシュ システム (L1/L2、RAM など) を理解し、適切に利用する

  11. ガベージ コレクターに委譲するよりも、メモリ管理を完全に制御することを優先する

  12. 高品質のケーブルを使用し、ケーブルをできるだけ短くし、ねじれやカールの数を減らします。

私の質問:ロー レイテンシー ネットワーキングに着手する際に、仲間の SO 関係者が重要だと信じていることは他にあるのだろうかと考えていました。

上記の点について自由に批判してください

4

3 に答える 3

8

ケーブルの品質は通常、ニシンのようなものです。ネットワークアナライザーを接続して、気にするのに十分な再送信が得られているかどうかを確認することについてもっと考えます. 非常に多く発生している場合は、発生している場所を特定し、問題の原因となっているケーブルを交換してください。再送信につながるエラーが発生しない場合、ケーブルは (事実上) レイテンシーに影響を与えません。

NIC および (特に) スイッチの大きなバッファーは、それ自体では待ち時間を短縮しません。実際、レイテンシを真に最小限に抑えるには、通常、大きなバッファーではなく、できるだけ小さなバッファーを使用する必要があります。データが処理されずにバッファに留まっていると、レイテンシがすぐに増加します。正直なところ、心配する価値はほとんどありませんが、それでも. 本当に遅延を最小限に抑えたい(そして帯域幅をあまり気にしない) 場合は、スイッチよりもハブを使用する方がよいでしょう (もう見つけるのは難しいですが、ネットワークの輻輳が十分に低い限り、遅延は確実に低くなります)。

複数の NIC は帯域幅を大幅に節約できますが、レイテンシーへの影響は一般的にごくわずかです。

編集: ただし、私の主なアドバイスは、スケール感をつかむことです。ネットワーク ケーブルを 1 フィート減らすと、約 1 ナノ秒節約できます。これは、2 つのアセンブリ言語命令によってパケット処理を高速化するのとほぼ同じ順序です。

結論: 他の最適化と同様に、遅延を大幅に削減する前に、どこで遅延が発生しているかを測定する必要があります。ほとんどの場合、ワイヤの長さを短くしても (1 つの例を使用すると)、気付くほどの違いはありません。単純に、最初は高速だからです。何かが 10 マイクロ秒かかる場合、それを 10 マイクロ秒以上高速化することはできません。したがって、10 マイクロ秒が時間のかなりの割合を占めるほど高速なものがない限り、攻撃する価値はありません。

于 2011-05-19T22:11:58.203 に答える
6

その他:

1: ユーザーランド ネットワーク スタックを使用する

2: 処理コードと同じソケットでサービス割り込み (共有キャッシュ)

3: バイト数が少し大きくても、固定長のプロトコルを優先します (解析が速くなります)。

4: ネットワークのバイト順の規則を無視し、ネイティブの順序付けのみを使用する

5: ルーチンとオブジェクト プール (特にガベージ コレクション言語) では決して割り当てない

6: できるだけバイトコピーをしないようにする (TCP 送信ではハード)

7: カットスルー スイッチング モードを使用する

8: ネットワーク スタックをハックして TCP スロー スタートを削除する

9: 巨大な TCP ウィンドウをアドバタイズします (ただし、使用しないでください)。これにより、反対側が一度に多くのインフライト パケットを持つことができます。

10: NIC 結合をオフにします (特に送信用) (必要に応じてアプリ スタックでパケット化します)

11: 光よりも銅線を好む

私は続けることができますが、それは人々に考えさせるべきです

私が同意しないもの:

1: ネットワーク ケーブルが問題になることはめったにありません (ケーブルの種類に関して例外があります)。

于 2011-08-02T04:25:48.697 に答える
3

これは少し明白かもしれませんが、これは私が満足している手法であり、UDP と TCP の両方で機能するので、それについて書きます。

1) 大量の送信データをキューに入れないようにします。具体的には、可能な限り最後の瞬間まで、メモリ内データ構造をシリアル化されたバイト バッファーにマーシャリングしないようにしてください。代わりに、送信ソケットが書き込み可能として select() する場合、その時点で関連する/ダーティなデータ構造の現在の状態を平坦化し、それらをすぐに send() します。そうすれば、送信側でデータが「蓄積」されることはありません。(また、カーネル内のデータ待ち行列を最小限に抑えるために、ソケットの SO_SNDBUF をできるだけ小さく設定してください)

2)データが何らかの方法でキー化されていると仮定すると、受信側でも同様のことができます。(データメッセージの読み取り、データメッセージの処理、繰り返し)ループを実行する代わりに、利用可能なすべてのデータメッセージを読み取り、それらをソケットが読み取ることができるデータがなくなるまで、キー付きデータ構造 (ハッシュ テーブルなど) を使用し、その後 (そのときだけ) データ構造を反復処理してデータを処理します。これの利点は、受信クライアントが受信データに対して重要な処理を行う必要がある場合、古い受信メッセージが自動的/暗黙的にドロップされ (それらの置換がキー付きデータ構造でそれらを上書きするため)、受信パケットが優先されることです。カーネルの着信メッセージ キューにバックアップしません。(もちろん、カーネルのキューがいっぱいになってパケットを破棄することもできますが、しかし、その後、プログラムは「古い」パケットを読み取って「新しい」パケットをドロップすることになります。これは通常、必要なことではありません)。さらなる最適化として、I/O スレッドがキー付きデータ構造を別の処理スレッドに渡して、処理によって I/O が保留されないようにすることができます。

于 2011-08-02T04:48:33.600 に答える