LinuxでUDPC++サーバーアプリを作成し、負荷テストを行って、処理できるクライアントの数を確認しています。毎秒2〜4の速度でパケットを送信する約150の同時クライアントでピークに達することがわかりました。
その後に追加されたクライアントにより、他のクライアントのパケットがドロップされます。
サーバー自体にストレスがかからず、CPUとメモリの10%未満しか使用していません。ネットワークにも、約15Kバイト/秒のストレスはまったくありません。パケットは、約200パケット/秒でサーバー(読み取りと書き込みの両方に1つのUDPソケットを使用)に到着します。サーバースレッド自体は、この負荷レベルで短時間スリープします。
質問:
ここでのボトルネックは何ですか?CPU、ネットワーク、サーバーコード自体はすべてストレスがないようです。OSはこの数のUDPパケットを処理できませんか?
ハードウェアは非常に低電力で、1.5MHzでシングルコアのPentiumに相当します。NICは1億ビット/秒です。Ubuntu11.1を実行しています。
この記事は関連している可能性があります:WindowsServer2008でのUDPパフォーマンスの上限
更新:サーバーはUDPソケットをセットアップしてから、3つのスレッドと2つのキューを作成します。ソケット読み取りの最初のスレッドブロックは次のようになります。
while (1)
{
recvfrom(this->socket, readBuf, BUFSIZE, 0, (sockaddr *)&address, &addressLen);
pushBack(this->inputQueue, message);
}
2番目のスレッドはinputQueueでスリープします。状態が通知されるとウェイクアップし、メッセージを処理します。処理されたメッセージをoutputQueueに送信します。
while (1)
{
sleepOnQ(this->inputQueue);
popFront(this->inputQueue);
processMessage();
pushBack(this->outputQueue, message);
}
3番目のスレッドはoutputQueueでスリープし、UDPソケットから宛先にメッセージを送信します。読み取りに使用されるのと同じソケットであることに注意してください。
while (1)
{
sleepOnQ(this->outputQueue);
popFront(this->outputQueue);
processMessage();
sendto(this->socket, message, ... );
}
クライアントおよびメッセージごとの処理量は少ないです。サーバーが毎秒200メッセージを処理しているときに述べたように、サーバーは本当に弱々しいCPUの約10%を使用しています。
システムのカーネルパラメータの一部を次に示します。
net.core.wmem_max = 114688
net.core.rmem_max = 114688
net.core.wmem_default = 114688
net.core.rmem_default = 114688
データ同期に関する詳細情報
これまでの答えから、2つのことが起こっていると思いました。
- OS読み取りバッファがいっぱいになっています。しかし、CPUが低い場合、これは発生しないはずです
- ただし、スレッドが他のイベントを待機している場合、#1が発生する可能性があります。そのため、ソケットを十分に速く読み取れません。
ロギングが問題になる可能性があります。ログをオフにして結果を報告してみます。ただし、おそらくもっと重要なのは、スレッド間のキューの競合です。CPUが低いため、スレッドはキューへのアクセスを待機するのに多くの時間を費やしている可能性があります。
このサーバーの最初の反復では、データのロックについて注意を払うようにしました。サーバーは非常に高速でしたが、800パケット/秒に達するとクラッシュしました。現在のバージョンでは、キュー全体がロックされます。たぶん私はスレッドを同期するためのより良い方法が必要です。
質問に答えました
ここで得た情報はとても役に立ちました。問題はテストクライアントの骨頭エラーでしたが、調査を行うことで、ここで提案された原因を取り除くことができました。
参考までに、これが私の結果です。クライアントの問題を修正すると、サーバーは70%のCPU使用率で約800パケット/秒を受け入れました。OSの読み取り/書き込みバッファを128Kから12MBに増やしました。読み取りバッファーがいっぱいかどうかはテストしませんでした。最高速度では、サーバーの読み取りスレッドが10回または20回の読み取りごとに短時間読み取りをブロックしていたため、OS読み取りバッファーが問題であったとは思えません。
800パケット/秒はまだ遅すぎるので、サーバーからログを削除しました。これは大きな違いを生みました。サーバーは、70%のCPUユーティリティで1400以上のクライアントから2900メッセージ/秒を受信できました。
また、読み取りスレッドがロックを待機しているかどうかをテストしました。最高速度でも、1ミリ秒以上待つ必要がないことがわかったので、2900メッセージ/秒の要因ではありませんでした。おそらくそれはより高速なCPU上にあるでしょう。
この時点で、サーバーはCPUにバインドされており、次のボトルネックを見つけるには、より強力なCPUを使用する必要があります。ご協力いただきありがとうございます!