GuilleSQL :: Microsoft SQL Server, SSIS, y más !!

IIS Deadlocks, Rendimiento, Threads y SharePoint


En algunas ocasiones, si trabajamos habitualmente con aplicaciones Web de IIS (como es el caso de SharePoint), podemos encontrarnos tanto con problemas de IIS Deadlocks, así como con problemas de rendimiento. Una forma de poder enfrentarnos a este tipo de problemas, es modificar algunos parámetros de configuración de Threading que podemos encontrar en el fichero Machine.config del Net Framework. El presente artículo describe esta solución, que en alguna ocasión puede resultarnos de gran utilidad.

La configuración de Threading que podemos realizar en el fichero Machine.Config, puede resultarnos de gran ayuda para enfrentarnos ante problemas de rendimiento en IIS (incluyendo IIS Deadlocks), y en consecuencia, de SharePoint.

Se trata de una configuración no demasiado conocida, y de la cual tenemos disponible alguna KB, entradas en los Blogs de MSDN y Technet, así como otras referencias variadas en la Web. Un buen ejemplo, serían los siguientes enlaces:

Básicamente se trata de reducir las peticiones (Requests) que se quedan encoladas (y en consecuencia, su tiempo de espera), para de este modo, aumentar la concurrencia del sistema, y con ello, aumentar el número de peticiones por segundo. Esta es una forma de conseguir mejorar el rendimiento de ASP.NET, consiguiendo una mayor concurrencia de nuestros servidores (mayor rendimiento), y minimizando los IIS DeadLocks.

IIS Deadlock

Además, el problema de los IIS Deadlocks puede producir un Reciclado del App Pool, que puede tardar más de lo habitual, y al final, entre unas cosas y otras nos encontramos con una indisponibilidad de varios minutos (bienvenido al mundo de las SLAs y las penalizaciones ;-).

Además, el problema de los IIS Deadlocks puede producir un Reciclado del App Pool, que puede tardar más de lo habitual, y al final, entre unas cosas y otras nos encontramos con una indisponibilidad de varios minutos

Un caso práctico: configurando Threads en el Machine.Config para SharePoint 2007 (ASP.NET 2.0 en IIS6)

Vamos a ver un caso práctico paso a paso de un SharePoint 2007 x86 sobre una Máquina Virtual con 4 Cores ejecutando Windows Server 2003 R2 SP2 x86 (es decir, IIS6). Lo primero es localizar el fichero Machine.Config, que encontraremos en ruta en la que tenemos instalado en .Net Framework, en nuestro caso particular C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG, aunque también podría ser C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\CONFIG para una máquina x64. Haremos una Copia de Seguridad del Machine.Config, para seguidamente editarlo. 

Vamos a ver un caso práctico paso a paso de un SharePoint 2007 x86 sobre una Máquina Virtual con 4 Cores ejecutando Windows Server 2003 R2 SP2 x86. Lo primero es localizar el fichero Machine.Config

Necesitamos configurar varios valores en el fichero Machine.Config, que por defecto no están, por lo que deberemos añadirlos en la mayoría de los casos, y configurarlos como deseemos. A continuación ponemos un ejemplo de una configuración genérica recomendada, la cual, puede ser o no la mejor opción para nuestros servidores (no hay que cegarse, estas recomendaciones no tienen por qué ser la mejor opción en todos los casos, se debe analizar cada caso por separado):

  • system.web\processModel, atributo maxWorkerThreads. Controla el número máximo de Worker Threads en el Thread Pool. Su valor por defecto es 2, mientras que el valor recomendado es 100. El valor que especifiquemos, será implícitamente multiplicado por el número de CPUs.
  • system.web\processModel, atributo maxIoThreads. Controla el número máximo de I/O Threads en el Thread Pool. Su valor por defecto es 2, mientras que el valor recomendado es 100. El valor que especifiquemos, será implícitamente multiplicado por el número de CPUs.
  • system.web\processModel, atributo minWorkerThreads. Controla el número mínimo de Worker Threads que deben estar disponibles en el Thread Pool. En aquellas ocasiones, en las que de repente es necesario disponer de una gran cantidad de Threads, puede ser interesante establecer esta propiedad, ya que de lo contrario el sistema podría no ser capaz de conseguir crear todos estos Threads en un tiempo aceptable, produciéndose algunas esperas. Su valor por defecto depende de la versión de Net Framework, mientras que el valor recomendado es maxWorkerThreads/2, es decir, 50.
  • system.web\processModel, atributo minIoThreads. Controla el número mínimo de I/O Threads que deben estar disponibles en el Thread Pool. En aquellas ocasiones, en las que de repente es necesario disponer de una gran cantidad de Threads, puede ser interesante establecer esta propiedad, ya que de lo contrario el sistema podría no ser capaz de conseguir crear todos estos Threads en un tiempo aceptable, produciéndose algunas esperas. Su valor por defecto depende de la versión de Net Framework, mientras que el valor recomendado es maxIoThreads/2, es decir, 50.
  • system.web\httpRuntime, atributo minFreeThreads. Determina cuantos Worker Threads y Completion Port Threads deben estar disponibles para poder iniciar una petición (Request) remota. Si no hay suficientes Threads, la petición será encolada. Su valor por defecto es 8, mientras que el valor recomendado es 88*N, donde N es el número de CPUs. En nuestro caso, tenemos 4 CPUs, por lo que el valor recomendado sería 352.
  • system.web\httpRuntime, atributo minLocalRequestFreeThreads. Determina cuantos Worker Threads y Completion Port Threads deben estar disponibles para poder iniciar una petición (Request) local. Si no hay suficientes Threads, la petición será encolada. Su valor por defecto es 4, mientras que el valor recomendado es 76*N, donde N es el número de CPUs. En nuestro caso, tenemos 4 CPUs, por lo que el valor recomendado sería 304.
  • system.net\connectionManagement, atributo maxconnection. Controla el número máximo de conexiones salientes HTTP que se pueden iniciar desde un cliente, teniendo en cuenta, que en esta ocasión el cliente es el propio ASP.NET. Su valor por defecto es 2, mientras que el valor recomendado es 12*N, donde N es el número de CPUs. En nuestro caso, tenemos 4 CPUs, por lo que el valor recomendado sería 48. Sin embargo, en nuestro caso de ejemplo vamos a especificar un valor de 100.

Hay que tener en cuenta que ASP.NET en teoría no ejecutará más del siguiente número de peticiones (Requests) en el mismo tiempo: (maxWorkerThreads*number of CPUs)-minFreeThreads. Por lo tanto, al utilizar esta configuración, se podrá ejecutar un máximo de 12 peticiones (Requests) por CPU. Con todo esto, deseamos realizar la siguiente configuración en el fichero Machine.Config.

<system.net>
  <connectionManagement>
    <add address="*" maxconnection="100" />
  </connectionManagement>
</system.net>
<system.web>
  <processModel autoConfig="true" maxWorkerThreads = "100" maxIoThreads = "100"
    minWorkerThreads = "50" minIoThreads = "50" />
  <httpRuntime minFreeThreads="352" minLocalRequestFreeThreads="304" />
</system.web>
Por lo tanto, modificaremos el fichero Machine.Config con estos valores, y guardaremos los cambios. No hace falta hacer IISRESET para que aplique, otra cosa, es que nos quedemos más tranquilos haciéndolo.

Por lo tanto, modificaremos el fichero Machine.Config con estos valores, y guardaremos los cambios. No hace falta hace IISRESET para que aplique

Y hemos acabado.

Monitorización básica: Prueba y Error

Si lo deseamos, podemos probar diferentes combinaciones de los anteriores parámetros del Machine.Config, y a la vez hacer Pruebas de Carga de nuestro sistema con las diferentes configuraciones, del mismo modo, que podemos monitorizar el sistema real antes de cambiar dichos parámetros, y monitorizarlo también después de cambiarlos, y así poder ver las diferencias.

Podemos realizar las pruebas de carga con diferentes herramientas, como el Microsoft WCAT (Web Capacity Analysis Tool) que podemos encontrar disponible en el Kit de Recursos del IIS, o también con Visual Studio. En cualquier caso, podremos monitorizar algunos contadores de rendimiento, como por ejemplo:

  • ASP.NET Apps v2.0.50727\Requests Executing
  • ASP.NET v2.0.50727\Requests Queued
  • ASP.NET v2.0.50727\Requests Current

A continuación se muestra un ejemplo de monitorización durante una pequeña prueba de carga con Microsoft WCAT sobre un MOSS 2007 x86, tomando los anteriores contadores, y algún que otro contador más.

Ejemplo de monitorización durante una pequeña prueba de carga con Microsoft WCAT sobre un MOSS 2007 x86, tomando los anteriores contadores, y algún que otro contador más

Los resultamos que obtendremos pueden depender del tipo de actividad, es decir, no es lo mismo peticiones largas que consuman poca CPU, que peticiones cortas que consuman mucha CPU. En función de qué tipo de peticiones ejecute nuestro sistema, puede interesarnos realizar una configuración u otra del Machine.Config.

¿Y qué más podemos hacer?

Aumentar el número de CPUs, o bien, el número de servidores de nuestra Granja (suponiendo que tenemos algún tipo de balanceo como NLB). Estaba claro. El tamaño importa.

Al menos, desde mi desconocimiento. Es decir, en las pruebas que he estado realizando, jugando con las diferentes configuraciones de Threading del Machine.Config en ASP.NET v2.0 sobre IIS6 con un SharePoint 2007 SP3, y realizando diversas pruebas de carga con Microsoft WCAT (Web Capacity Analysis Tool), he observado:

  • VM Win 2K3 x86 con 1 CPU. A partir de las 24 peticiones (Requests) concurrentes (contador Requests Executing), se empiezan a encolar (contador Requests Queued). WCAT sólo es capaz de alcanzar aproximadamente 1200 peticiones a la Home en 30 segundos.
  • VM Win 2K3 x86 con 2 CPUs. A partir de las 48 peticiones (Requests) concurrentes (contador Requests Executing), se empiezan a encolar (contador Requests Queued). WCAT sólo es capaz de alcanzar aproximadamente 2400 peticiones a la Home en 30 segundos.
  • Servidor físico Win 2K3 x86 con 8 CPUs. A partir de las 192 peticiones (Requests) concurrentes (contador Requests Executing), se empiezan a encolar (contador Requests Queued). No quiero mostrar los resultados de WCAT, ya que se trata de una Granja totalmente distinta a la anterior, y considero que no son datos comparables.

Curioso, ¿verdad?

Despedida y Cierre

En cualquier caso, este tipo de configuraciones resultan algo abstractas. A través del presente artículo, he intentado dejar un resumen junto con un muestrario de enlaces a otras entradas en la Web, para facilitar su comprensión, pero no deja de ser un tema algo complejo y abstracto, que en muchas ocasiones, lo acabaremos resolviendo por prueba y error.

Poco más por hoy. Como siempre, confío que la lectura resulte de interés.

 


]
[Autor: GuilleSQL]



Miembros de
Miembros de GITCA (Global IT Community Association)

Menu de Usuario
  Iniciar Sesión
  Registrarse
  Restablecer Contraseña
  Ventajas de Registrarse

Acerca de
  Contigo desde Oct 2007
  771 usuarios registrados
  86146 pageloads/mes
  Ranking Alexa 498160

Social Networks
Sigue a Portal GuilleSQL en Linkedin !!
Sigue a Portal GuilleSQL en Twitter !!



Archivo

Marzo de 2019 (1)
Octubre de 2018 (1)
Julio de 2018 (1)
Junio de 2018 (4)
Mayo de 2018 (5)
Abril de 2018 (3)
Marzo de 2018 (2)
Febrero de 2018 (7)
Enero de 2018 (1)
Diciembre de 2017 (15)
Noviembre de 2017 (7)
Junio de 2017 (3)
Mayo de 2017 (1)
Marzo de 2017 (3)
Enero de 2017 (4)
Junio de 2016 (1)
Mayo de 2016 (2)
Abril de 2016 (2)
Septiembre de 2015 (2)
Agosto de 2015 (2)
Junio de 2015 (10)
Mayo de 2015 (4)
Abril de 2015 (8)
Marzo de 2015 (11)
Octubre de 2014 (3)
Septiembre de 2014 (7)
Agosto de 2014 (5)
Julio de 2014 (2)
Mayo de 2014 (4)
Abril de 2014 (4)
Marzo de 2014 (4)
Febrero de 2014 (1)
Enero de 2014 (5)
Diciembre de 2013 (8)
Noviembre de 2013 (2)
Octubre de 2013 (7)
Septiembre de 2013 (6)
Agosto de 2013 (1)
Julio de 2013 (6)
Junio de 2013 (11)
Mayo de 2013 (7)
Abril de 2013 (6)
Febrero de 2013 (5)
Enero de 2013 (7)
Diciembre de 2012 (12)
Noviembre de 2012 (13)
Octubre de 2012 (5)
Septiembre de 2012 (3)
Agosto de 2012 (6)
Julio de 2012 (4)
Junio de 2012 (1)
Mayo de 2012 (2)
Abril de 2012 (7)
Marzo de 2012 (16)
Febrero de 2012 (9)
Enero de 2012 (5)
Diciembre de 2011 (10)
Noviembre de 2011 (10)
Octubre de 2011 (4)
Septiembre de 2011 (5)
Agosto de 2011 (2)
Julio de 2011 (2)
Junio de 2011 (4)
Mayo de 2011 (2)
Abril de 2011 (6)
Marzo de 2011 (4)
Febrero de 2011 (10)
Enero de 2011 (5)
Diciembre de 2010 (6)
Noviembre de 2010 (4)
Octubre de 2010 (8)
Septiembre de 2010 (4)
Agosto de 2010 (1)
Julio de 2010 (3)
Mayo de 2010 (5)
Abril de 2010 (6)
Marzo de 2010 (8)
Febrero de 2010 (3)
Enero de 2010 (1)
Diciembre de 2009 (9)
Noviembre de 2009 (14)
Octubre de 2009 (2)
Septiembre de 2009 (8)
Agosto de 2009 (2)
Julio de 2009 (10)
Junio de 2009 (9)
Mayo de 2009 (10)
Abril de 2009 (9)
Marzo de 2009 (3)
Febrero de 2009 (2)
Enero de 2009 (3)
Noviembre de 2008 (2)
Octubre de 2008 (2)
Septiembre de 2008 (2)
Agosto de 2008 (5)
Julio de 2008 (5)
Junio de 2008 (1)
Mayo de 2008 (3)
Abril de 2008 (2)
Marzo de 2008 (2)
Febrero de 2008 (2)
Enero de 2008 (5)
Noviembre de 2007 (2)
Octubre de 2007 (2)






Copyright © 2007 GuilleSQL, todos los derechos reservados.