2011-05-25 25 views
3

我開發了一種與遠程SIP端點交換RTP數據包的VoIP媒體服務器。它需要很好地擴展 - 儘管我最初擔心我的C#實現不會接近它所替代的C++版本,但我使用了各種分析器來磨練實現,並且性能非常接近。使用異步UDP操作的.NET IOCP ThreadPool開銷

我通過創建可重用對象池來取消大多數對象分配,我使用ReceiveFromAsync和SendToAsync來發送/接收數據報,並且我正在使用生產者/消費者隊列在系統周圍傳遞RTP數據包。在配備2個2.4GHz Xeon處理器的機器上,我現在可以處理大約1000個併發流,每個流每秒發送/接收50個數據包。但是,迭代配置文件/調整/配置文件讓我着迷 - 我相信在那裏有更多的效率!

觸發處理的事件是在SocketAsyncEventArgs上調用的Completed委託 - 它通過處理管道發送RTP數據包。

其餘的挫折是在IOCP線程池中似乎存在很大的開銷。分析器顯示只有72%的包含採樣時間在'我的代碼'中 - 之前的時間似乎是線程池開銷(下面的堆棧幀)。

所以,我的問題是:

  1. 我失去了我的理解是什麼?
  2. 可以減少這種開銷嗎?
  3. 是否有可能取代異步套接字函數使用的線程池來使用自定義輕量級線程池,並且開銷較小?每秒在Windows
 
100% MediaGateway 

95.35% Thread::intermediateThreadProc(void *) 

88.37% ThreadNative::SetDomainLocalStore(class Object *) 

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(struct ADID) 

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

86.05% AppDomainStack::ClearDomainStack(void) 

83.72% ThreadPoolNative::CorWaitHandleCleanupNative(void *) 

83.72% [email protected]@@84 

83.72% DispatchCallDebuggerWrapper(unsigned long *,unsigned long,unsigned long *,unsigned 
__int64,void *,unsigned __int64,unsigned int,unsigned char *,class 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% [email protected] 

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(class System.Threading.ExecutionContext,class System.Threading.ContextCallback,object) 

72.09% System.Net.Sockets.SocketAsyncEventArgs.ExecutionCallback(object) 

72.09% System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(class System.Net.Sockets.SocketAsyncEventArgs) 
+0

我不知道任何配置選項或類似的,允許以任何方式調整IOCP線程池。我想你所能做的就是優化代碼中的72%。 – dtb 2011-05-25 22:28:34

+1

@dtb不幸的是,大約40%的時間隨後花在Socket中。SendToAsync - 所以我只剩下32%的比賽了 - 我覺得我已經儘可能多的去了那一場比賽。也許我已經接近.NET的限制,只需要擴展硬件。 – MikeBrom 2011-05-26 07:44:13

+0

這可能只是分析的人工產物。你確定你推送的數據超過服務器可以處理的數量嗎?有很多樂觀鎖定和自旋鎖定,當負載足夠大時有助於性能,但在分析時會產生奇怪的數據。很可能是因爲沒有完成任何工作,只是等待下一個數據。也可能是它偶然碰巧是GC凍結過程的地方。異步代碼對配置文件來說非常棘手 - 我有很多「問題」,這些問題都是分析本身的工件。 – Luaan 2015-02-24 13:41:09

回答

1

50000包是相當不錯的,我要說的是,硬件和操作系統是縮放更顯著的問題。不同的網絡接口有不同的限制,英特爾服務器網卡主要具有高性能和良好的驅動程序跨平臺,但與Windows相比,Broadcom在Windows上沒有良好的記錄。 Windows的高級核心網絡API只有在驅動程序支持這些功能時才能啓用,而Broadcom已經證明是一家只支持較新硬件的高級功能的公司,儘管支持其他操作系統的舊設備。

我會開始研究多個NIC,例如使用四Intel服務器NIC並使用Windows高級網絡API將一個NIC綁定到每個處理核心。從理論上講,你可以通過一個NIC發送50,000個數據,通過另一個NIC發送50,000個數據。

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

不過看來你真的沒有一個基準來衡量對代碼的效率。我希望看到與不運行VoIP有效載荷的服務器進行比較,運行在TCP傳輸而不是UDP上,並且在其他操作系統上運行以比較IP堆棧和API效率。

+0

謝謝史蒂夫 - 我同意硬件是我的nex端口,儘管我希望先簡化代碼。不知道我是否明白你的基準方面的含義 - 沒有任何有效載荷,沒有任何資料需要描述,RTP也不使用TCP。 – MikeBrom 2011-06-14 09:20:16

0

只是添加一些信息 - 我最近發現IOCP線程池中存在一個可能會影響性能的錯誤:請參閱http://support.microsoft.com/kb/2538826中'cause'部分的第3點。這可能對你的情況有效。