TCPは、送信されるすべてのパケットに対して新しい接続を開きますか?


15

これはばかげた質問かもしれませんが、私と数人の仲間がTCPの潜在的な制限について議論しています。クライアントをリッスンし(ゲートウェイのように)、単一の接続されたkafkaパブリッシャーを介してすべての接続されたクライアントデータを1つのトピックにルーティングするアプリケーションがあります。

私の仲間の1人は、TCPが送信するすべてのメッセージに対して新しい接続を確立するため、このゲートウェイにとって問題になると言っています(kafkaではなく、基礎となるトランスポートプロトコル自体が問題です)、毎回新しいポートが必要です。これらのクライアントメッセージ(ギガバイト)を送信するレートで、kafkaは読み込むポートを使い果たしますか?

私は数年にわたって開発を行ってきましたが、これについては聞いたことがないので、TCPがどのように機能するかについてのより低いレベルの理解を得たいと思っています。私の理解では、TCP接続を確立すると、その接続はアプリケーションによってタイムアウトになるか、サーバーまたはクライアントによって強制的に閉じられるまで開いたままになります。この接続を介して送信されるデータはストリームであり、3 V(ボリューム、速度、種類)に関係なく新しい接続を開いたり閉じたりしません。

ポートに関する限り、1つのポートがブロードキャストに使用され、内部ファイル記述子ポートは、個々のクライアントの読み取り/書き込みのためにアプリケーションが管理するものです。TCPが書き込むすべてのパケットに対して新しい接続を確立することを理解していません。

この質問が直接的なものではないか、あいまいすぎる場合は、事前におaび申し上げます。私は本当に困惑していて、誰かが私の同僚が言っていることに対して、より多くの文脈を提供できることを望んでいますか?


13
あなたはあなたの友人が言っていることを誤解していると思います。TCPはそのようなことを行いませんが、特定のクライアントが通過させたいメッセージごとに新しいTCP接続を作成する可能性があります
ホッブズ

13
TCPは、新しい接続を開くために複数のパケットを必要とするため、パケットごとに新しい接続を開くことはできませんでした。また、TCPにはメッセージの概念がないため、各メッセージに対して新しい接続を開くことができませんでした。あなたの相棒はとても混乱しています。最も基本的な概念であるTCPについて理解する最も重要なことは、TCPがバイトストリームプロトコルであることです。
デビッドシュワルツ

1
バディの議論は必ずしも間違っているわけではありません。アプリケーションレベルのキープアライブでポートを再利用しない場合や、クライアントが多すぎる場合、一時ポートが不足する可能性があります。この問題を回避する方法があります:SO_REUSEADDRソケットをより速く閉じるために使用する、一時ポートの範囲を増やすなど。さらにTCP_FASTOPEN、いくつかのOSレベルのトグルを使用して、TCPの他のよく知られている制限を回避できます。いずれにせよ、テスト対象のワークロードがない場合でも、TCPの制限について議論する意味はありません。
user1643723

回答:


22

私の仲間の1人は、TCPが送信するすべてのメッセージに対して新しい接続を確立するため、このゲートウェイにとって問題になると言っています(kafkaではなく、基礎となるトランスポートプロトコル自体が問題です)、毎回新しいポートが必要です。これらのクライアントメッセージ(ギガバイト)を送信するレートで、kafkaは読み込むポートを使い果たしますか?

あなたの友人はひどく混乱しています。TCPはストリーム指向のプロトコルです。メッセージの概念はありません。もちろん、IP層でパケットを使用しますが、アプリケーションにとってこれは実装の詳細です。それはそうすることは理にかなって、どこTCPはパケット境界を挿入するごとに必ず一度ではありませんwrite()send()。同様に、read()またはへの呼び出しの間に複数のパケットを受信した場合、連続するパケットを結合しますrecv()

言うまでもなく、このストリーム指向の設計は、すべての送信が新しい接続を確立すると完全に機能しなくなります。したがって、新しい接続を確立する唯一の方法は、接続を手動で閉じて再度開くことです。

(実際には、TCPの上に構築されたほとんどのプロトコルには、HTTP要求や応答などのメッセージに似たものがありますが、TCPはそのような構造を認識しません。

友達がUDPを考えていた可能性があります。UDPはメッセージを持っていますが、コネクションレスでもあります。ほとんどのソケット実装では、UDPソケットをリモートホストに「接続」できますが、これはIPアドレスとポートを繰り返し指定する必要を回避するための便利な方法です。実際にはネットワークレベルでは何もしません。それでも、UDPの下で通信しているピアを手動で追跡できます。しかし、それを行う場合、「接続」と見なされるものを決定するのはOSではなく問題です。すべてのメッセージで「接続」を再確立する場合は、それを行うことができます。ただし、おそらくあまり良い考えではありません。


9

私の理解では、TCP接続を確立すると、その接続はアプリケーションによってタイムアウトになるか、サーバーまたはクライアントによって強制的に閉じられるまで開いたままになります。

TCPの観点から見ると、クライアントやサーバーはありません(クライアント/サーバーは、ここでは話題にならないアプリケーションの概念です)。TCPはピア間の接続を確立し、両方のピアは、いずれかのピアが閉じるか、非アクティブからタイムアウトするまで、接続上で送受信できます。

この接続を介して送信されるデータはストリームであり、3 V(ボリューム、速度、種類)に関係なく新しい接続を開いたり閉じたりしません。

状況を混乱させているのは、ブラウザなどの一部のアプリケーションが、Webページの要素などを同時に読み込むために複数の接続を開くことです。

TCPは、送信するすべてのセグメントに対して新しい接続を開きませんが、アプリケーションは複数のTCP接続を開く場合があります。また、TCP接続が閉じられると、接続で使用されているTCPポートが解放され、再び使用できるようになります。この回答はいくつかの情報を提供し、TCPのRFCを示しています。


2
TCPには、接続を開始したパートナー(「クライアント」と呼ばれることが多い)と他のパートナー(「サーバー」と呼ばれることが多い)があります。もちろん、接続が確立された後は、この違いは問題になりません。
パウロEbermann

2
@PaŭloEbermann、クライアントまたはサーバーに関するTCP RFCには何もありません。クライアント/サーバーの概念は、アプリケーションの概念です。ここで話題になっているのは、OSIレイヤー4以下のプロトコルであり、これらのプロトコルにはクライアントやサーバーはありません。実際、クライアント(TCP接続を開くクライアント)であると想定されるものは、実際にはアプリケーションサーバーである可能性があります。セキュリティチェックや更新などを行うために、クライアントへのTCP接続を開始するサーバーがあります。
ロンモーピン

7

いいえ、TCP は送信されるすべてのパケットに対して新しい接続を開く必要ありません。

HTTP持続接続を使用して複数のパケットを送信できます。ここで、

...単一の要求/応答ペアごとに新しい接続を開くのではなく、複数のHTTP要求/応答を送受信するための単一のTCP接続[使用されます]。

添付されているのは、複数の接続(接続ごとに1つのオブジェクトを送信するために確立された多くの接続)と永続的な接続(1つの接続が確立され、複数のオブジェクトが送信される)の違いを示す図です:

複数の接続と永続的な接続

ソース:https : //www.vcloudnine.de/how-to-dramatically-improve-website-load-times/


7
この答えは混乱している層のようです。HTTP要求/応答が単一のパケットになることはめったにありません。
バーマー

2
言うまでもなく、すべての「開く」は実際には3つの矢印(syn、synack、ack)であり、すべての「閉じる」は別の4(fin、ack 2xサーバーおよびクライアント)なので、実際にパケットごとの接続がある場合、オーバーヘッドすぐに追加されます。
htmlcoderexe

5

TCPの動作の解釈は正しいです。

あなたの友人が言ったことに関して、私はここに2つの可能性を見る:

  1. 友人は、各メッセージが新しい接続で送信されるアプリケーション層の制限について言及していたと誤解していました(これは必ずしも珍しいことではありません。ソフトウェアによっては、この動作を決定できる場合とできない場合があります。使用しているスタック);

  2. あなたの友人は間違っています。


5

他の人が指摘しているように、TCPは、接続を任意の時間開いたままにして、その間に任意の数の「メッセージ」をいずれかの方向に交換することを絶対に許可します。つまり、その機能が利用されているかどうかを判断するのは、最終的にはアプリケーション(クライアントとサーバーの両方)の責任です。

既存のTCP接続(ソケット)を再利用するには、クライアントアプリケーションはそのソケットを開いたままにして、さらにデータを書き込む必要があるときに使用する必要があります。クライアントがこれを行わず、代わりに古いソケットを破棄し、必要なたびに新しいソケットを開く場合、実際に新しい接続を強制的に実行します。これにより、頻繁に行うとクライアントまたはサーバーのリソースの問題が発生する可能性がありますいずれかのTCPスタックの接続プール。

同様に、サーバーは、その側でソケットを開いたままにして、さらにデータを待つのに十分なスマートでなければなりません。クライアントと同様に、より多くのデータを送信したいフォールトトレラントクライアントが新しいソケットを開く以外に選択肢がないため、同じ問題を引き起こすソケットを閉じるオプションがあります。

最後に、他の人が述べたように、TCPはストリーム指向です。フレーミングは一切ありません。1つのピアが特定の方法でデータを書き込んだため(たとえば、1つの1024バイトの書き込み呼び出しに2つの256バイトの書き込み呼び出しが続く)、他のピアが同じサイズのチャンクでデータを読み取ることを保証しません(たとえば、1536バイトすべてを取得する可能性があります) 1回の読み取り呼び出しで)。したがって、生のTCPソケットを介して複数の「メッセージ」を送信する場合は、独自のフレーミングプロトコルを提供して、さまざまなメッセージの輪郭を描く必要があります。これを行う簡単な方法は確かにありますが、この問題を解決するためにTCPの上に構築された多くのプロトコルがあるので、一般的には賢明ではありません。詳細については、https//blog.stephencleary.com/2009/04/message-framing.htmlをご覧ください。


2

あなたの友人はTCPではなくHTTPについて話していたと思います。

HTTPはもともとステートレスプロトコルでした。各HTTP要求は個別のTCP接続を使用します。これが、セッションを実装するためにCookie(または同様のもの)が必要な理由です。


0

「単一接続で毎回新しいポートが必要」と述べましたが、同じネットワーク環境でPAT技術を使用して多くのクライアントが組織外のサーバーに接続していると解釈します。PATの制限は65535(IPv4アドレスのTCPセッション制限)です。それが本当なら、あなたには限界があります。

TCPは、送信されるすべてのパケットに対して新しい接続を開きますか?いいえ、TCPセッションが有効である限り有効ではありません。そして...


0

はTCPに関する優れたウィキペディアのページが好きです。ポート番号がどうなるかを明確に示しています。偶然にも、リソースの使用に関する役立つ章が含まれています。

リソース使用量

ほとんどの実装では、セッションを実行中のオペレーティングシステムプロセスにマップするテーブルにエントリを割り当てます。TCPパケットにはセッション識別子が含まれていないため、両方のエンドポイントはクライアントのアドレスとポートを使用してセッションを識別します。パケットを受信するたびに、TCP実装はこのテーブルで検索を実行して宛先プロセスを見つける必要があります。テーブル内の各エントリは、伝送制御ブロックまたはTCBと呼ばれます。これには、エンドポイント(IPおよびポート)、接続の状態、交換されているパケットに関する実行中のデータ、およびデータを送受信するためのバッファーに関する情報が含まれています。

サーバー側のセッション数はメモリによってのみ制限され、新しい接続が到着すると増加しますが、クライアントは最初のSYNをサーバーに送信する前にランダムなポートを割り当てる必要があります。このポートは会話全体を通して割り当てられたままであり、各クライアントのIPアドレスからの発信接続の数を効果的に制限します。アプリケーションが不要な接続を適切に閉じられない場合、クライアントはリソースを使い果たし、他のアプリケーションからであっても新しいTCP接続を確立できなくなります。

要するに、TCPは1つの非常に有限なリソースを使用します。これは、クライアント上のポートの数です(これは、TCPヘッダーのポートフィールドのサイズ、16ビットによって制限されます)。

そのため、クライアントが多くのTCP接続を閉じずに並行して開く場合、TCP ポートを使い果たす可能性があります。問題はクライアント側でのみ発生し、接続が同じまたは異なるサーバーIPアドレスまたはサーバーポートであるかどうかは関係ありません。

あなたの設定では、多くのクライアントリクエストを受け取る1つのアプリケーションがあるようです(これらクライアントはこれを使用してアプリケーションにイベントを記録し、その間でTCPチャネルを開いたままにしない場合があります)、Kafkaブローカー(非常に簡単に個々のTCP接続である可能性があります)このように実装することを選択した場合)。この場合、ボトルネックは(パフォーマンスではなくリソースの点で)クライアントから大量のリクエストを同時に取得する場合です(サーバー側では1つのポートしか必要ないため、問題はありません)そして、あなたはあなたのカフカへの膨大な数の転送リクエストをオープンします、そしてカフカはそれらを十分に速く処理することができず、あなたは16ビット以上の接続を同時にオープンすることになります。

あなたはここで自分の裁判官です。アプリケーションを確認し、毎回(おそらくREST APIプロキシ経由で)個別のリクエストでKafkaに接続しているかどうかを確認してください。そうすれば、クライアントの数が膨大であれば、あなたは確かに危険にさらされています。

65k未満の少数のクライアントしかない場合、および/またはKafkaブラウザーへの単一の接続を維持する場合は、問題ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.