C# - Cuándo usar subprocesos estándar, ThreadPool y TPL en un servidor de alta actividad


He estado leyendo mucho sobre threading últimamente, ya que estoy buscando desarrollar un servidor TCP escalable de alto rendimiento capaz de manejar hasta 10,000-20,000 clientes, cada cliente de los cuales se comunica constantemente bidireccional con el servidor con un sistema basado en comandos. El servidor recibirá un comando y ejecutará una sola (o muchas) tareas según el comando. Mi pregunta es cómo hacer un uso apropiado de las construcciones. NET threading para una variedad de situaciones, ejecutar tareas que pueden tardar entre un minuto y varias horas, dependiendo del trabajo que se esté realizando.

Lo que más me confunde es el hecho de que en todas partes que leo, veo algo como "usar un Subproceso creado manualmente (o un grupo de subprocesos personalizado) para manejar tareas 'de larga duración', y usar TPL para tareas de corta duración, o tareas que requieren procesamiento paralelo."¿Qué es exactamente una tarea de larga duración? Es que 5 segundos, 60 segundos, una hora?

Con qué marco de tiempo debería estar usando cada uno de estos tres métodos de creación de hilos:

  • Hilos creados manualmente
  • La clase. NET ThreadPool
  • TPL

Otro problema que he contemplado es el siguiente say digamos que mi servidor tiene de hecho 20,000 clientes conectados, cada uno de los cuales envía 1 comando (que podría traducirse en una o muchas tareas) por segundo. Incluso con un hardware potente, no hay posibilidad de que pueda estar empujando demasiado alto de una carga de trabajo en cualquier grupo de subprocesos / ¿cola de elementos de trabajo que tengo, generando así una excepción OutOfMemoryException después de que la cola se llene lentamente al máximo?

Cualquier visión sería muy apreciada.

Author: slashp, 2011-03-13

4 answers

En realidad, para ese escenario todos son secundarios; lo primero que debe mirar es asyc-IO, también conocido como .BeginRead(...), etc.; esto le permite minimizar el número de subprocesos esperando en los puertos de finalización de IO, mucho más eficiente.

Una vez que tenga un mensaje completo, a esa escala arrojaría el mensaje a una cola de subprocesos personalizada/sincronizada. Tendría un número controlado de subprocesos regulares (no subprocesos de grupo o IOCP) que dan servicio a esa cola procesar cada elemento.

Sucede que estoy haciendo algo similar (escala más baja) en este momento; para evitar que la memoria explote, he limitado la cola de trabajo; si se llena (es decir, los trabajadores no pueden mantenerse al día), entonces puede bloquear IOCP por un pequeño tiempo, tal vez con un tiempo de espera que finalmente le diga al cliente "demasiado ocupado" en la capa IOCP.

 17
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-13 09:43:41

Lo que más me confunde es el el hecho de que en todas partes que leo, veo algo así como " utilizar un creado manualmente Hilo (o grupo de hilos personalizados) a manejar tareas 'de larga duración', y utilizar TPL para tareas de corta duración, o tareas que requieren procesamiento paralelo."

Extraño consejo, o tal vez usted mal citado un poco. Un hilo también es capaz de procesar en paralelo, y con el TPL puede crear una tarea con la opción LongRunning. Lo que queda es que no debes inicia tareas largas en ThreadPool.

¿Qué es exactamente una tarea de larga duración? Es que 5 segundos, 60 segundos, un hora?

El TPL se ejecuta en la parte superior del ThreadPool y el TP creará nuevos hilos a un máximo de 2 por segundo. So long-running is > = 500 ms


Incluso con hardware potente, no es hay una posibilidad de que podría estar empujando demasiado alto de una carga de trabajo en lo que sea thread pool / work item queue I have,

Sí, sin roscar la herramienta puede ampliar su capacidad real...

Con clientes de 20k probablemente necesitará una granja de servidores, una opción para incluir en su diseño temprano...

Así que probablemente deberías darle un buen vistazo a WCF antes de adentrarte en los sockets.

 10
Author: Henk Holterman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-13 09:58:20

La sugerencia de Marcs es la forma en que lo haría. Pero si las tareas tardan más de un segundo y los clientes envían una solicitud por segundo, la cola aumentaría constantemente.

En ese caso usaría un servidor como fachada que recibe todas las solicitudes de los clientes y les envía respuestas de forma asíncrona.

El servidor pondría todas las solicitudes en una cola de mensajes que es leída por varios otros servidores. Esos servidores manejan las solicitudes y ponen la respuesta en otra cola de mensajes que es leída por el primer servidor.

Otra solución sería usar un servidor de equilibrio de carga.

 7
Author: jgauffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-13 09:51:35

Parece que está construyendo un servidor que dará servicio a miles de solicitudes simultáneas, cada una de ellas de larga duración en términos de minutos a horas.

Normalmente, haga que las cargas de trabajo de subprocesos sean lo suficientemente cortas como para completarse como máximo en unos pocos segundos. En cualquier momento, comenzará a acaparar los recursos del servidor y afectará seriamente la escalabilidad de su servidor. Tener decenas de miles de hilos bloqueados en operaciones de larga duración, o hacer esas operaciones de larga duración simultáneamente, definitivamente matará su escalabilidad.

No estoy seguro de cuánto tiempo de CPU está consumiendo en cada larga ejecución. Esto afectará su diseño, por ejemplo:

Si cada ejecución prolongada está bloqueando principalmente las E/S, puede usar un subproceso para esperar en el puerto de finalización de E/S superpuestas o E/S, y luego activar nuevos subprocesos para procesar E/S completadas (hasta un límite limitado). Necesitarás tener un número límite de subprocesos para dar servicio a las conexiones en espera.

Si cada operación de larga duración espera a que otras operaciones completo, considere Windows Workflow Foundation.

Si cada operación de larga duración consume CPU, no desea que se ejecuten demasiadas de ellas a la vez o se trastornará su servidor. En este caso, use MSMQ y / o TPL para poner en cola tareas y asegúrese de que solo unas pocas se estén ejecutando al mismo tiempo.

En todos estos, parece que está manteniendo abierta la conexión del cliente. Lo peor que puede hacer es mantener un bloqueo de hilo para cada conexión. Usted tendrá que implementar estrategias de agrupación de subprocesos para usar solo un número limitado de subprocesos para dar servicio a todas las conexiones pendientes.

 4
Author: Stephen Chung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-13 09:53:35