2012-06-19 15 views
5

Estoy trabajando en un nuevo servicio para ejecutar QA para las propiedades web múltiples de nuestras empresas, y me he encontrado con un problema de concurrencia de red interesante. Para aumentar el rendimiento, estoy usando el TPL para crear HttpWebRequests a partir de una gran colección de urls para que puedan ejecutarse en paralelo; sin embargo, parece que no puedo encontrar dónde está el cuello de botella en el proceso.Problemas concurrentes de rendimiento de solicitud web

Mis observaciones hasta el momento:

  • yo puede conseguir a un máximo de alrededor de 25-30 hilos paralelos a través de la TPL
  • La CPU nunca se rompe 5-6% para el servicio (que se ejecuta en de 1 - 4 núcleos, con y sin H/T)
  • El uso de NIC nunca se rompe 2-3%
  • El tráfico de red global no parece verse afectado (otros usuarios no se quejan, las pruebas de velocidad se ejecutan al mismo tiempo don ' t muestra mucho de un efecto)
  • Velocidad no no cambia mucho entre ejecutarse en nuestra red de oficina (15Mbps) o en nuestro centro de datos (100 + Mbps)
  • Obtengo un poco de rendimiento al descargar de varios hosts a la vez en lugar de muchas páginas de un host.

posibles puntos de dolor:

  • CPU (número de núcleos o hilos de hardware)
  • NIC
  • Max permitió número de HttpWebRequests concurrentes
  • LAN
  • WAN
  • Router/Switch/Load balancer

Entonces la pregunta es:

Obviamente ahora hay manera de descargar la totalidad de Internet en cuestión de minutos, pero estoy interesado en saber dónde está el cuello de botella está en un escenario como este y lo que, si cualquier cosa, se puede hacer para superarlo.

Como nota al margen, actualmente estamos utilizando un servicio de terceros para rastrear, pero estamos limitados por ellos de alguna manera y desearíamos más flexibilidad. Algo sobre salsa secreta corporativa o poison on the tip of the arrow ... :)

+0

¿Puedes publicar algunos detalles sobre tu código? Estoy ejecutando un rastreador con 100 subprocesos paralelos sin problemas. Estoy en .NET 4 y el servidor no es mucho. Estoy usando NCrawler en el back-end. –

+0

El código es realmente muy simple. Uso Parallel.ForEach para recorrer un conjunto de URL (cadenas). La acción crea una HttpWebRequest y luego vuelca los resultados en un ConcurrentBag. Por cierto, NCrawler parece interesante; Lo comprobaré. Gracias por el consejo. –

+0

Hay un límite en el número de HttpWebRequest simultáneas para el mismo host IIRC –

Respuesta

7

tengo la fuerte sospecha una de las siguientes es la causa:

  1. Se está ejecutando en el límite de conexiones por defecto. Compruebe el valor de ServicePointManager.DefaultConnectionLimit. Le recomiendo configurarlo en un valor prácticamente infinito como 1000.
  2. El TPL no está comenzando tantos hilos como sea necesario para saturar la red. Tenga en cuenta que los servidores web remotos pueden tener una gran cantidad de latencia. Mientras espera, su hilo no está cargando en la red.

El TPL no garantiza ningún grado mínimo de paralelismo (DOP). Es una lástima porque a veces es necesario controlar el grado de paralelismo exactamente cuando se trabaja con IO.

Le recomiendo que inicie manualmente un número fijo de hilos para hacer su IO porque esa es la única forma de garantizar un DOP específico. Necesitas experimentar con el valor exacto. Podría estar en el rango de 50 a 500. Puede reducir el tamaño de pila predeterminado de sus subprocesos para ahorrar memoria con tantos subprocesos.

+0

Gracias por los consejos. Sin embargo, lo que me gusta del TPL es que permite fácilmente que una sola compilación funcione en una amplia variedad de máquinas sin tener que escribir mucho código para administrar los hilos de hardware numéricos. –

+3

@SteveKonves esto es cierto, pero solo se aplica al trabajo vinculado a CPU. Su código parece que debe estar vinculado a la red. El TPL se interpondrá activamente en su camino y administrará mal los recursos. – usr

+1

primer punto del usr es casi seguro que sea el caso. Independientemente de cómo gestiones tus hilos, tendrás que tener cuidado con el DefaultConnectionLimit. – MNGwinn

1

Tal vez esté llegando al límite de las conexiones TCP o no se deshaga de las conexiones correctamente; en cualquier caso, intente utilizar algo como JMeter para ver el máximo rendimiento HTTP simultáneo que puede obtener.

1

El código es realmente muy simple. Yo uso Parallel.ForEach para recorrer a través de una colección de URL (cadenas). La acción crea una HttpWebRequest y luego vuelca los resultados en un ConcurrentBag. Por cierto, NCrawler parece interesante; Lo comprobaré. Gracias por el consejo.

Porque con Parallel.ForEach es imposible controlar el número de hilos, entonces sugiero al menos cambiar a ThreadPool.

Puede usar QueueUserWorkItem para asignar trabajo hasta que su colección de tareas esté completamente presionada a los subprocesos de trabajo o hasta que el método devuelva falso (no más subprocesos en el grupo).

Con ThreadPool puede controlar el número máximo de hilos para asignar con SetMaxThreads.

+1

¿Por qué sugerirías usar 'ThreadPool' directamente si puedes usar' Task's? Ellos son mucho más convenientes. Y no creo que la cantidad máxima de subprocesos en el grupo de subprocesos sea un problema aquí, generalmente es lo suficientemente grande. – svick

+0

No lo sé. Supongo que estoy acostumbrado a usar ThreadPool. –

Cuestiones relacionadas