Затраты.NET IOCP ThreadPool с асинхронными операциями UDP

Я разработал медиа-сервер VoIP, который обменивается RTP-пакетами с удаленными конечными точками SIP. Он должен хорошо масштабироваться - и хотя я изначально был обеспокоен тем, что моя реализация C# не будет приближаться к версии C++, которую она заменяет, я использовал различные профилировщики, чтобы отточить реализацию, и производительность довольно близка.

Я исключил большинство распределений объектов, создав пулы многократно используемых объектов, я использую ReceiveFromAsync и SendToAsync для отправки / получения дейтаграмм, и я использую очереди производителя / потребителя для передачи пакетов RTP по системе. На машине с 2 процессорами Xeon 2,4 ГГц теперь я могу обрабатывать около 1000 одновременных потоков, каждый из которых отправляет / получает 50 пакетов в секунду. Тем не менее, итеративный профиль / настройка / профиль меня зацепил - и я уверен, что где-то там больше эффективности!

Событием, запускающим обработку, является делегат Completed, вызываемый для SocketAsyncEventArgs, который, в свою очередь, отправляет пакеты RTP через конвейер обработки.

Остальное разочарование заключается в том, что в пуле потоков IOCP, по-видимому, имеются значительные издержки. Профилировщик показывает, что только 72% времени Inclusive Sample приходится на "мой код" - время до этого, по-видимому, связано с накладными расходами пула потоков (стеки кадров ниже).

Итак, мои вопросы:

  1. Я что-то упустил в моем понимании?
  2. Можно ли уменьшить эти накладные расходы?
  3. Можно ли заменить пул потоков, используемый функциями асинхронного сокета, на пользовательский, легкий пул потоков с меньшими издержками?
100% MediaGateway

95,35% Тема:: промежуточный_процесс (пустота *)

88,37% ThreadNative::SetDomainLocalStore(класс Object *)

88,37% BindIoCompletionCallbackStub(длинная без знака, длинная без знака, структура _OVERLAPPED *)

86.05% BindIoCompletionCallbackStubEx(длинная без знака, длинная без знака, структура _OVERLAPPED *,int)

86,05% ManagedThreadBase::ThreadPool(структура ADID,void (*)(void *),void *)

86,05% CrstBase::Enter(пусто)

86,05% AppDomainStack::PushDomain(структура ADID)

86.05% Thread::ShouldChangeAbortToUnload(класс Frame *, класс Frame *)

86,05% AppDomainStack::ClearDomainStack(пусто)

83,72% ThreadPoolNative::CorWaitHandleCleanupNative(void *)

83,72% __CT??_R0PAVEEArgumentException@@@84

83.72% DispatchCallDebuggerWrapper(длинная без знака *, длинная без знака, длинная без знака *, без знака 
__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, значение типа System.Threading.NativeOverlapped*)

76,74% System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(uint32,uint32, значение типа System.Threading.NativeOverlapped*)

76,74% System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(значение типа System.Net.Sockets.SocketError,int32, значение типа System.Net.Sockets.SocketFlags)

74,42% System.Threading.ExecutionContext.Run(класс System.Threading.ExecutionContext, класс System.Threading.ContextCallback, объект)

72,09% System.Net.Sockets.SocketAsyncEventArgs.ExecutionCallback(объект)

72,09% System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(класс System.Net.Sockets.SocketAsyncEventArgs)

2 ответа

50 000 пакетов в секунду в Windows - это неплохо, я бы сказал, что аппаратное обеспечение и операционная система - более важные проблемы для масштабирования. Разные сетевые интерфейсы накладывают разные ограничения: сетевые адаптеры Intel имеют преимущественно высокую производительность с хорошими кроссплатформенными драйверами, однако Broadcom не имеют хороших результатов в Windows по сравнению с Linux. Расширенные API-интерфейсы ядра сети Windows доступны только в том случае, если драйверы поддерживают эти функции, и Broadcom доказала, что является компанией, которая включает расширенные функции только для более нового оборудования, несмотря на поддержку более старых устройств из других операционных систем.

Я бы начал исследовать несколько сетевых адаптеров, например, с четырехядерной серверной сетевой платой Intel и использовать расширенные сетевые API-интерфейсы Windows для привязки одного сетевого адаптера к каждому ядру обработки. Теоретически вы можете отправить 50 000 через один сетевой адаптер и 50 000 через другой.

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

Однако, похоже, что у вас нет базовых показателей для оценки эффективности кода. Я ожидаю увидеть сравнение с серверами, не использующими полезную нагрузку VoIP, работающими на транспорте TCP вместо UDP и работающими в других операционных системах для сравнения стека IP и эффективности API.

Просто добавьте немного информации - я недавно обнаружил, что в пуле потоков IOCP присутствует ошибка, которая может повлиять на вашу производительность: см. Пункт 3 раздела "причина" в http://support.microsoft.com/kb/2538826. Это может быть действительно для вашего случая.

Другие вопросы по тегам