Linuxには、UDPソケットを開いてメッセージを待つJavaアプリがあります。
負荷が高い状態で数時間後、パケット損失が発生します。つまり、パケットはカーネルで受信されますが、アプリでは受信されません(スニファーで損失パケットが表示され、netstatでUDPパケットが失われ、パケットが表示されません)アプリのログにあります)。
ソケットバッファを拡大しようとしましたが、これは助けにはなりませんでした。その後、パケットを失い始めましたが、それだけです。
デバッグのために、OS udpバッファーがどのくらいいっぱいになっているかを、いつでも知りたいです。 Googleで検索しましたが、何も見つかりませんでした。手伝って頂けますか?
追伸皆さん、UDPが信頼できないことは承知しています。ただし、私のコンピューターはすべてのUDPメッセージを受信しますが、アプリはそれらの一部を消費できません。アプリを最大限に最適化したいのですが、それが質問の理由です。ありがとう。
Linuxはファイル/proc/net/udp
および/proc/net/udp6
は、開いているすべてのUDPソケットをリストします(それぞれIPv4およびIPv6用)。両方で、列tx_queue
およびrx_queue
発信および着信キューをバイト単位で表示します。
すべてが期待どおりに機能している場合、通常、これら2つの列にはゼロ以外の値は表示されません。アプリケーションがパケットを生成するとすぐにネットワーク経由で送信され、ネットワークからパケットが到着するとすぐにアプリケーションが起動しますそしてそれらを受け取ります(recv
呼び出しはすぐに戻ります)。 rx_queue
アプリケーションがソケットを開いているが、データを受信するためにrecv
を呼び出していない場合、またはそのようなデータを十分に速く処理していない場合は、上に移動します。
UDPは完全に実行可能なプロトコルです。適切な仕事に適した適切なツールの同じ古いケースです!
UDPデータグラムを待ってから、別のデータグラムを待つために戻る前に処理するプログラムがある場合、処理経過時間は、データグラムの最悪の場合の到着率よりも常に速い必要があります。そうでない場合は、UDPソケット受信キューがいっぱいになり始めます。
これは短いバーストに対しては許容できます。キューは、実行するはずのデータグラムをキューに入れるという、本来の目的を果たします。しかし、平均到着率が定期的にキューにバックログを引き起こす場合は、プログラムを再設計するときです。ここには2つの主な選択肢があります:巧妙なプログラミング手法による経過処理時間の短縮、および/またはプログラムのマルチスレッド化。プログラムの複数のインスタンス間で負荷分散を行うこともできます。
前述のように、Linuxでは、procファイルシステムを調べて、UDPの状態に関するステータスを取得できます。たとえば、cat
the /proc/net/udp
ノード、私はこのようなものを得る:
$ cat /proc/net/udp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
40: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 3466 2 ffff88013abc8340 0
67: 00000000:231D 00000000:0000 07 00000000:0001E4C8 00:00000000 00000000 1006 0 16940862 2 ffff88013abc9040 2237
122: 00000000:30D4 00000000:0000 07 00000000:00000000 00:00000000 00000000 1006 0 912865 2 ffff88013abc8d00 0
これから、ユーザーID 1006が所有するソケットがポート0x231D(8989)でリッスンしており、受信キューが約128KBであることがわかります。私のシステムでは128KBが最大サイズなので、これは私のプログラムが到着するデータグラムに追いつくのが非常に弱いことを示しています。これまでに2237のドロップがありました。つまり、UDPレイヤーはこれ以上データグラムをソケットキューに入れることができず、それらをドロップする必要があります。
時間の経過とともにプログラムの動作を見ることができます。を使用して:
watch -d 'cat /proc/net/udp|grep 00000000:231D'
また、netstatコマンドはほぼ同じことを行うことに注意してください:netstat -c --udp -an
私のweenieプログラムの解決策は、マルチスレッドにすることです。
乾杯!
rx_queueは、任意の瞬間のキューの長さを通知しますが、キューがどれだけいっぱいになっているか、つまり最高水準点を通知しません。この値を継続的に監視する方法はなく、プログラムで値を取得する方法もありません( DPソケットのキューデータの量を取得する方法 を参照)。
キューの長さの監視を想像できる唯一の方法は、キューを独自のプログラムに移動することです。つまり、2つのスレッドを開始します。1つはできるだけ速くソケットを読み取り、データグラムをキューにダンプします。もう1つは、このキューからプルしてパケットを処理するプログラムです。もちろん、これは、各スレッドが別々のCPU上にあることを保証できることを前提としています。これで、独自のキューの長さを監視し、最高水準点を追跡できます。
プロセスは簡単です:
必要に応じて、アプリケーションプロセスを一時停止します。
UDPソケットを開きます。必要に応じて、/proc/<PID>/fd
を使用して実行中のプロセスからスナッグできます。または、このコードをアプリケーション自体に追加して信号を送信することもできます。もちろん、すでにソケットが開いています。
recvmsg
をできるだけ早くタイトループで呼び出します。
取得したパケット/バイト数をカウントします。
これにより、現在バッファリングされているデータグラムはすべて破棄されますが、アプリケーションが破損した場合、アプリケーションは既に破損しています。