2017-02-06 32 views
1

boost::asioを使用して、接続ごとの通信モデルを非同期IOベースのTCPサーバーに移行しました。この変更の理由は、古いモデルが十分に拡張できなかったためです。私たちは永続的に約2kの持続的な接続を平均して毎月増え続ける傾向があります。非同期IO TCPサーバーの最適なワーカースレッド数

私の質問は、完了ハンドラのio_serviceキュー(仮想CPUコアの数)をポーリングするワーカースレッドの理想的な数は何ですか?

少数を選択すると、サーバーが十分に迅速に消費されず、クライアントがメッセージを送信する速度に対応できなくなることがあります。

このような状況でワーカースレッドを動的に追加することは理にかなっていますか?

更新: おそらくそれは私の実装であるが、私は混乱ブーストASIOのドキュメンタリーのこの文の一部を見つける:なスレッドごとの接続(同期のみのアプローチが必要になるなど

実装戦略コンテキスト切り替え、同期化、およびCPU間でのデータ移動が増加するため、システム のパフォーマンスが低下する可能性があります。非同期操作の場合、 は、 オペレーティングシステムスレッド(通常は限られたリソース)の数を最小限に抑えることによってコンテキスト切り替えのコストを避けることができ、 は、 というイベントを持つコントロールの論理スレッドのみをアクティブにすることができます。

あなたはXコアを持つマシン上で完了イベントをポンピングXのスレッドを持っているかのように - 私の接続がドン私永続的である場合1)あなたは)各スレッドは専用のCPUと2を取得することをいかなる保証もありませんasync_readを実行するスレッドが完了ハンドラを実行するスレッドと同じであるという保証はありません。完全に非ブロッキングI/O、L1キャッシュに完全に収まるワーキングセットとの理想的な状況、及び物理的システムでない他のプロセスにおいて

void Connection::read { 
    boost::asio::async_read(socket, boost::asio::buffer(buffer, 18), 
          boost::bind(&Connection::handleRead, shared_from_this(), 
          boost::asio::placeholders::error, 
          boost::asio::placeholders::bytes_transferred)); 
} 

void Connection::handleRead(const boost::system::error_code &error, 
               std::size_t bytes_transferred) { 
    // processing of the bytes 
    ... 
    // keep processing on this socket 
    read(); 
} 
+3

「これは依存している」ということを除いて、これは明らかに答えることはできません。私が言うことは、あなたの理想的なデザインは1つでなければならないということです.NICの帯域幅の飽和までインストールされたNICあたり2つ以上のカーネルスレッドはありません。それを超えている場合は、あなたのソフトウェアを非効率的でないようにリファクタリングする必要があります。 nginxが10 Gbps NICのスケーラビリティをどのように実装したかを読んだり、ASIOコンサルタントの専門家を招いてアドバイスしてください。 –

+2

人は(必ずしもあなたではない)1つのスレッドの能力を大幅に過小評価する傾向があります。 1つのスレッドで実行できる作業量は巨大です。 1)余りにも多くのスレッドからのコンテキスト切り替えにより、待ち時間とスループットの問題が発生します。2)完了イベントをポンピングするスレッドが少なすぎるために発生する遅延が大きく、スループットが低い、3)スレッドが過剰になり、 CPUキャッシュのパフォーマンスが低下します。あなたのワークロードに対するこれらすべてのバランスはスイートスポットであり、それを見つける唯一の方法は実験と測定です。 – hoodaticus

+0

私はこれについてさらにフォローアップしたいと思います。非同期IOアプローチで見られるのは、待ち時間の問題は予想どおりになくなっていますが、1秒あたりのctxtスイッチの絶対数は、接続モデルごとにスレッドで使用していたものの約10倍です。言い換えると、完了イベントをポンピングする24 IOスレッドは、古いモデルの〜1kワーカースレッドよりも多くのコンテキストスイッチを生成します。あなたはこれについてあなたの考えを共有できますか? – ladaManiak

答えて

1

、各スレッドは、プロセッサコアの全体の資源を使用します。このような状況では、理想的なスレッド数は論理コアごとに1つです。

I/Oのいずれかの部分がブロックしている場合は、コアが空き状態にならないように、コアの数より多くのスレッドを追加するのが理にかなっています。スレッド時間の半分がブロックされた場合、コアごとにほぼ2つのスレッドが必要です。スレッド時間の75%が費やされた場合は、コアごとに3または4が必要です。コンテキスト切り替えのオーバーヘッドは、この目的のためにブロックされます。

私はMicrosoftがこれについて盲目的に推測しなければならない場合、コアあたり2〜4つのスレッドを使用する傾向があることに気付きました。この決定を下すための予算に応じて、コアごとに1つのスレッドで開始し、スループット(秒当たりのリクエスト数)とレイテンシ(最小、最大、平均応答時間)を測定して、私がスイートスポットに当たるまで。

この値を動的に調整することは、根本的に異なるプログラムを扱う場合にのみ意味があります。予測可能な作業負荷のために、ハードウェアには、作業の量が増えてもあまり変化しないはずのスイートスポットがあります。汎用Webサーバーを作成している場合は、おそらく動的調整が必要です。

関連する問題