3

我开发了一个 VoIP 媒体服务器,它与远程 SIP 端点交换 RTP 数据包。它需要很好地扩展——虽然我最初担心我的 C# 实现不会接近它所取代的 C++ 版本,但我使用了各种分析器来磨练实现并且性能非常接近。

我通过创建可重用对象池来限制大多数对象分配,我正在使用 ReceiveFromAsync 和 SendToAsync 来发送/接收数据报,并且我正在使用生产者/消费者队列在系统中传递 RTP 数据包。在具有 2 个 2.4GHz Xeon 处理器的机器上,我现在可以处理大约 1000 个并发流,每个流每秒发送/接收 50 个数据包。然而,迭代的配置文件/调整/配置文件让我着迷——我相信那里的效率更高!

触发处理的事件是在 SocketAsyncEventArgs 上调用的 Completed 委托——它反过来通过处理管道发送 RTP 数据包。

剩下的挫败感是 IOCP 线程池中似乎有很大的开销。分析器显示只有 72% 的包容性采样时间在“我的代码”中——之前的时间似乎是线程池开销(下面的堆栈帧)。

所以,我的问题是:

  1. 我的理解是否遗漏了什么?
  2. 是否有可能减少这种开销?
  3. 是否可以替换异步套接字函数使用的线程池以使用开销更少的自定义轻量级线程池?
100% 媒体网关

95.35% 线程::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(无效)

86.05% AppDomainStack::PushDomain(struct 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 *,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% _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,对象)

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

72.09% System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(类 System.Net.Sockets.SocketAsyncEventArgs)
4

2 回答 2

1

在 Windows 上每秒 50,000 个数据包相当不错,我想说硬件和操作系统是更重要的扩展问题。不同的网络接口有不同的限制,英特尔服务器网卡主要是高性能和良好的跨平台驱动程序,但与 Linux 相比,博通在 Windows 上的记录并不好。仅当驱动程序支持这些功能时,Windows 的高级核心网络 API 才会启用,而 Broadcom 已被证明是一家只为较新硬件启用高级功能的公司,尽管支持其他操作系统的旧设备。

我将开始研究多个 NIC,例如使用四块英特尔服务器 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 效率的服务器进行比较。

于 2011-06-13T14:56:03.350 回答
0

也添加一些信息 - 我最近发现 IOCP 线程池中存在可能影响您的性能的错误:请参阅http://support.microsoft.com/kb/2538826中“原因”部分的第 3 点。它可能对您的情况有效。

于 2011-09-27T13:25:11.660 回答