type - summary example c#




Consejos/técnicas para tomas de servidor C#de alto rendimiento (7)

Como otros han sugerido, la mejor forma de implementar esto sería hacer que el código del cliente enfrente sea asíncrono. Utilice BeginAccept () en el TcpServer () para que no tenga que generar manualmente un hilo. Luego use BeginRead () / BeginWrite () en la secuencia de red subyacente que obtiene del TcpClient aceptado.

Sin embargo, hay una cosa que no entiendo aquí. Dijiste que estas son conexiones de larga vida y una gran cantidad de clientes. Suponiendo que el sistema ha alcanzado el estado estable, donde tiene sus clientes máximos (por ejemplo, 70) conectados. Tienes 70 hilos para escuchar los paquetes del cliente. Entonces, el sistema aún debe ser receptivo. A menos que su aplicación tenga pérdidas de memoria / identificador y se esté quedando sin recursos para que su servidor esté buscando. Me gustaría poner un temporizador en la llamada a Aceptar () donde se inicia un hilo de cliente y ver cuánto tiempo lleva. Además, iniciaría taskmanager y PerfMon, y supervisaría "Pool no paginado", "Memoria virtual", "Recuento de control" para la aplicación y vería si la aplicación tiene problemas de recursos.

Si bien es cierto que ir a Async es el camino correcto, no estoy seguro si realmente resolverá el problema subyacente. Supervisaría la aplicación como sugerí y me aseguraré de que no haya problemas intrínsecos de pérdida de memoria y de identificadores. En este sentido, "BigBlackMan" de arriba tenía razón, necesita más instrumentación para continuar. No sé por qué fue votado negativamente.

Tengo un servidor .NET 2.0 que parece tener problemas de escalado, probablemente debido a un diseño deficiente del código de manejo de socket, y estoy buscando orientación sobre cómo podría rediseñarlo para mejorar el rendimiento.

Escenario de uso: 50 - 150 clientes, alta velocidad (hasta 100s / segundo) de mensajes pequeños (10s de bytes cada uno) hacia / desde cada cliente. Las conexiones de los clientes son de larga vida, generalmente horas. (El servidor es parte de un sistema comercial. Los mensajes del cliente se agregan en grupos para enviar a un intercambio en un número menor de conexiones de socket 'salientes', y los mensajes de confirmación se envían a los clientes a medida que el intercambio procesa cada grupo .) SO es Windows Server 2003, el hardware es 2 x 4-core X5355.

Diseño de socket de cliente actual: un TcpListener genera un hilo para leer cada socket de cliente a medida que los clientes se conectan. Los subprocesos bloquean en Socket.Receive , analizan los mensajes entrantes y los insertan en un conjunto de colas para su procesamiento por la lógica del servidor central. Los mensajes de acuse de recibo se envían nuevamente a través de los sockets de los clientes utilizando Socket.BeginSend asincrónico. Socket.BeginSend llamadas desde los hilos que hablan al lado de la Socket.BeginSend .

Problemas observados: a medida que el conteo de clientes ha crecido (ahora 60-70), hemos comenzado a ver demoras intermitentes de hasta 100 segundos o milisegundos mientras enviamos y recibimos datos hacia y desde los clientes. (Registramos marcas de tiempo para cada mensaje de acuse de recibo, y podemos ver brechas largas ocasionales en la secuencia de marca de tiempo para grupos de acks del mismo grupo que normalmente salen en un total de pocos ms).

El uso general de la CPU del sistema es bajo (<10%), hay mucha RAM libre, y la lógica del núcleo y la del lado de salida (cara del intercambio) funcionan bien, por lo que el problema parece estar aislado del código del socket del cliente . Existe un ancho de banda de red amplio entre el servidor y los clientes (LAN gigabit), y hemos descartado problemas de red o de capa de hardware.

Cualquier sugerencia o sugerencia de recursos útiles sería muy apreciada. Si alguien tiene algún consejo de diagnóstico o depuración para averiguar exactamente qué es lo que está mal, también sería genial.

Nota: Tengo el artículo Winsock de MSDN Magazine : Acérquese más con cables con tomas de alto rendimiento en .NET , y he echado un vistazo al componente Kodart "XF.Server": parece incompleto en el mejor de los casos.


El Socket.BeginConnect y Socket.BeginAccept son definitivamente útiles. Creo que usan las llamadas ConnectEx y AcceptEx en su implementación. Estas llamadas envuelven la negociación de conexión inicial y la transferencia de datos en una transición de usuario / kernel. Como el búfer de envío / recepción inicial ya está listo, el kernel puede simplemente enviarlo, ya sea al host remoto o al espacio de usuario.

También tienen una lista de oyentes / conectores listos que probablemente da un poco de impulso al evitar la latencia involucrada con el espacio de usuario que acepta / recibe una conexión y la entrega (y todas las conmutaciones de usuario / kernel).

Para utilizar BeginConnect con un buffer, parece que debe escribir los datos iniciales en el socket antes de conectarse.


Los retrasos aleatorios intermitentes de ~ 250 ms podrían deberse al algoritmo de Nagle utilizado por TCP. Intenta inhabilitar eso y mira lo que sucede.


Mucho de esto tiene que ver con muchos subprocesos que se ejecutan en su sistema y el kernel que le da a cada uno de ellos un segmento de tiempo. El diseño es simple, pero no escala bien.

Probablemente debería considerar el uso de Socket.BeginReceive que se ejecutará en los grupos de subprocesos .net (puede especificar de alguna manera el número de subprocesos que usa) y luego presionando sobre una cola desde la devolución de llamada asincrónica (que puede ejecutarse en cualquiera de Hilos de .NET). Esto debería darte un rendimiento mucho más alto.


No tengo una respuesta, pero para obtener más información, sugiero rociar tu código con temporizadores y registrar el promedio y el tiempo máximo para las operaciones sospechosas, como agregar a la cola o abrir un socket.

Al menos de esa manera tendrá una idea de qué mirar y dónde comenzar.


Tuve el mismo problema hace 7 u 8 años y pausas de 100 ms a 1, el problema fue la recolección de basura ... Tenía unos 400 Meg en uso de 4 gigas PERO había muchos objetos.

Terminé almacenando mensajes en C ++, pero podrías usar el caché ASP.NET (que solía usar COM y los sacó del montón)


Una cosa que quisiera eliminar es que no es algo tan simple como el recolector de basura en ejecución. Si todos sus mensajes están en el montón, está generando 10000 objetos por segundo.

Tome una lectura de la recolección de basura cada 100 segundos

La única solución es mantener sus mensajes fuera del montón.