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();
}
「これは依存している」ということを除いて、これは明らかに答えることはできません。私が言うことは、あなたの理想的なデザインは1つでなければならないということです.NICの帯域幅の飽和までインストールされたNICあたり2つ以上のカーネルスレッドはありません。それを超えている場合は、あなたのソフトウェアを非効率的でないようにリファクタリングする必要があります。 nginxが10 Gbps NICのスケーラビリティをどのように実装したかを読んだり、ASIOコンサルタントの専門家を招いてアドバイスしてください。 –
人は(必ずしもあなたではない)1つのスレッドの能力を大幅に過小評価する傾向があります。 1つのスレッドで実行できる作業量は巨大です。 1)余りにも多くのスレッドからのコンテキスト切り替えにより、待ち時間とスループットの問題が発生します。2)完了イベントをポンピングするスレッドが少なすぎるために発生する遅延が大きく、スループットが低い、3)スレッドが過剰になり、 CPUキャッシュのパフォーマンスが低下します。あなたのワークロードに対するこれらすべてのバランスはスイートスポットであり、それを見つける唯一の方法は実験と測定です。 – hoodaticus
私はこれについてさらにフォローアップしたいと思います。非同期IOアプローチで見られるのは、待ち時間の問題は予想どおりになくなっていますが、1秒あたりのctxtスイッチの絶対数は、接続モデルごとにスレッドで使用していたものの約10倍です。言い換えると、完了イベントをポンピングする24 IOスレッドは、古いモデルの〜1kワーカースレッドよりも多くのコンテキストスイッチを生成します。あなたはこれについてあなたの考えを共有できますか? – ladaManiak