3

リモート SIP エンドポイントと RTP パケットを交換する VoIP メディア サーバーを開発しました。適切にスケーリングする必要があります。最初は、私の C# 実装が置き換えられる C++ バージョンに近づかないのではないかと懸念していましたが、さまざまなプロファイラーを使用して実装を磨き上げたところ、パフォーマンスはかなり近くなりました。

再利用可能なオブジェクトのプールを作成することで、ほとんどのオブジェクト割り当てを排除しました。ReceiveFromAsync と SendToAsync を使用してデータグラムを送受信し、プロデューサー/コンシューマー キューを使用してシステム内で RTP パケットを渡しています。2 x 2.4GHz Xeon プロセッサを搭載したマシンで、約 1000 の同時ストリームを処理できるようになりました。各ストリームは毎秒 50 パケットを送受信します。しかし、反復的なプロファイル/微調整/プロファイルにはまってしまいました - そして、どこかでもっと効率的であると確信しています!

処理をトリガーするイベントは、SocketAsyncEventArgs で呼び出される Completed デリゲートです。次に、処理パイプラインを介して RTP パケットを送信します。

残りのフラストレーションは、IOCP スレッドプールにかなりのオーバーヘッドがあるように見えることです。プロファイラーは、インクルーシブ サンプル時間の 72% のみが「私のコード」にあることを示しています。それ以前の時間は、スレッドプールのオーバーヘッドのようです (以下のスタック フレーム)。

だから、私の質問は次のとおりです。

  1. 私の理解に何か欠けていますか?
  2. このオーバーヘッドを削減することは可能ですか?
  3. 非同期ソケット関数で使用されるスレッドプールを置き換えて、オーバーヘッドの少ないカスタムの軽量スレッドプールを使用することは可能ですか?
100% メディアゲートウェイ

95.35% Thread::intermediateThreadProc(void *)

88.37% ThreadNative::SetDomainLocalStore(クラス オブジェクト *)

88.37% BindIoCompletionCallbackStub(unsigned long,unsigned long,struct _OVERLAPPED *)

86.05% BindIoCompletionCallbackStubEx(unsigned long,unsigned long,struct _OVERLAPPED *,int)

86.05% ManagedThreadBase::ThreadPool(struct ADID,void (*)(void *),void *)

86.05% CrstBase::Enter(void)

86.05% AppDomainStack::PushDomain(構造体 ADID)

86.05% Thread::ShouldChangeAbortToUnload(class Frame *,class Frame *)

86.05% AppDomainStack::ClearDomainStack(ボイド)

83.72% ThreadPoolNative::CorWaitHandleCleanupNative(void *)

83.72% __CT??_R0PAVEEArgumentException@@@84

83.72% DispatchCallDebuggerWrapper(unsigned long *,unsigned long,unsigned long *,unsigned)
__int64,void *,unsigned __int64,unsigned int,unsigned char *,クラス ContextTransitionFrame *)

83.72% DispatchCallBody(unsigned long *,unsigned long,unsigned long *,unsigned __int64,void *,unsigned __int64,unsigned int,unsigned char *)

83.72% MethodDesc::EnsureActive(void)

81.40% _CallDescrWorker@20

81.40% System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint32,uint32,valuetype System.Threading.NativeOverlapped*)

76.74% System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(uint32,uint32,valuetype System.Threading.NativeOverlapped*)

76.74% System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess (valuetype System.Net.Sockets.SocketError,int32,valuetype System.Net.Sockets.SocketFlags)

74.42% System.Threading.ExecutionContext.Run(クラス System.Threading.ExecutionContext,クラス System.Threading.ContextCallback,object)

72.09% System.Net.Sockets.SocketAsyncEventArgs.ExecutionCallback(オブジェクト)

72.09% System.Net.Sockets.SocketAsyncEventArgs.OnCompleted (クラス System.Net.Sockets.SocketAsyncEventArgs)
4

2 に答える 2

1

Windows での毎秒 50,000 パケットはかなり良い値です。ハードウェアとオペレーティング システムは、スケーリングにとってより重要な問題であると言えます。ネットワーク インターフェイスが異なれば、制限も異なります。インテル サーバー NIC は、クロス プラットフォームに優れたドライバーを備えた優れたパフォーマンスを発揮しますが、Broadcom は Linux と比較して Windows での実績がありません。Windows の高度なコア ネットワーキング API は、ドライバーが機能をサポートしている場合にのみ有効になります。Broadcom は、他のオペレーティング システムの古いデバイスをサポートしているにもかかわらず、新しいハードウェアの高度な機能のみを有効にする企業であることを示しています。

たとえば、クワッド Intel サーバー NIC を使用して複数の NIC の調査を開始し、Windows の高度なネットワーク API を使用して 1 つの NIC を各処理コアにバインドします。理論的には、ある NIC を介して 50,000 を送信し、別の NIC を介して 50,000 を送信できます。

http://msdn.microsoft.com/en-us/library/ff568337(v=VS.85).aspx

ただし、コードの効率を測定するためのベースラインが実際にはないようです。IP スタックと API の効率を比較するために、VoIP ペイロードを実行していないサーバー、UDP の代わりに TCP トランスポートで実行しているサーバー、および他のオペレーティング システムで実行しているサーバーとの比較を期待します。

于 2011-06-13T14:56:03.350 に答える
0

情報を追加するだけです。最近、パフォーマンスに影響を与える可能性のある IOCP スレッド プールにバグが存在することを発見しました。 http://support.microsoft.com/kb/2538826の「原因」セクションのポイント 3 を参照してください。あなたの場合には有効かもしれません。

于 2011-09-27T13:25:11.660 に答える