reiniciar reciclar reciclando reciclaje practices condiciones best application aplicaciones asp.net iis iis-7 asp.net-mvc-3 application-pool

asp.net - reciclando - reciclar pool de aplicaciones iis



Cómo saber por qué se recicla un grupo de aplicaciones IIS (4)

Fondo:

He implementado una aplicación ASP.NET MVC 3 que funciona en mi máquina en un proveedor de alojamiento compartido y estoy descubriendo algunos problemas que parecen estar relacionados con el grupo de aplicaciones que se recicla. El host ha configurado el reciclaje para que ocurra en cualquiera de estas circunstancias:

  • El uso de memoria excede los 200MB
  • El uso de la CPU supera el 75% (probablemente durante un período sostenido)
  • 20 minutos de inactividad

Las restricciones son más relajadas en mi máquina de desarrollo, por lo que no vi este tipo de reciclaje durante el desarrollo. No tengo acceso de administrador al cuadro de alojamiento compartido (es comprensible), por lo que no puedo leer el registro de eventos para ver por qué ocurre este reciclaje.

Pregunta:

¿Hay alguna manera de averiguar por qué mi aplicación fue reciclada (en Application_End por ejemplo) para poder registrarla y ayudar a mi depuración?


Investigación - 1

Primero intenté usar System.Web.ProcessModelInfo.GetCurrentProcessInfo() y System.Web.ProcessModelInfo.GetHistory(int) . Los resultados de estos métodos devuelven información como el PID, la hora de inicio, la edad, el estado y el uso máximo de la memoria. Desafortunadamente, estos no estaban disponibles en mi entorno de alojamiento:

HttpException 0x80004005 - Las métricas de proceso están disponibles solo cuando el modelo de proceso ASP.NET está habilitado. Cuando se ejecuta en versiones de IIS 6 o más nuevas en el modo de aislamiento de procesos de trabajo, esta función no es compatible.

Sin embargo, este enfoque podría funcionar para otros, así que si estás en esta situación, dale una oportunidad.

Investigación - 2

La propiedad System.Web.Hosting.HostingEnvironment.ShutdownReason es una enumeración con muchos valores, pero desafortunadamente todos los casos que describo en mi pregunta están agrupados en un solo valor de enumeración:

ApplicationShutdownReason.HostingEnvironment : el entorno de alojamiento cierra el dominio de la aplicación.

Investigación - 3

ScottGu tiene un enfoque en su blog (que es el mismo código que Kev publicó ) que utiliza la reflexión para acceder al estado interno de la aplicación HttpApplication . Desafortunadamente, en este caso, solo informa el mismo detalle que el # 2 anterior:

_shutDownMessage = HostingEnvironment initiated shutdown HostingEnvironment caused shutdown _shutDownStack = at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace() at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal() at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand() at System.Web.Hosting.PipelineRuntime.StopProcessing()


A continuación encontrará un buen código en http://mitchelsellers.com/blogs/2007/03/15/logging-aspnet-application-restarts.aspx

// obtain the shutdown reason System.Web.ApplicationShutdownReason shutdownReason = System.Web.Hosting.HostingEnvironment.ShutdownReason; string shutdownDetail = ""; //Evaluate which option caused the error switch (shutdownReason) { case ApplicationShutdownReason.BinDirChangeOrDirectoryRename: shutdownDetail = "A change was made to the bin directory or the directory was renamed"; break; case ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename: shutdownDetail = "A change was made to the App_browsers folder or the files contained in it"; break; case ApplicationShutdownReason.ChangeInGlobalAsax: shutdownDetail = "A change was made in the global.asax file"; break; case ApplicationShutdownReason.ChangeInSecurityPolicyFile: shutdownDetail = "A change was made in the code access security policy file"; break; case ApplicationShutdownReason.CodeDirChangeOrDirectoryRename: shutdownDetail = "A change was made in the App_Code folder or the files contained in it"; break; case ApplicationShutdownReason.ConfigurationChange: shutdownDetail = "A change was made to the application level configuration"; break; case ApplicationShutdownReason.HostingEnvironment: shutdownDetail = "The hosting environment shut down the application"; break; case ApplicationShutdownReason.HttpRuntimeClose: shutdownDetail = "A call to Close() was requested"; break; case ApplicationShutdownReason.IdleTimeout: shutdownDetail = "The idle time limit was reached"; break; case ApplicationShutdownReason.InitializationError: shutdownDetail = "An error in the initialization of the AppDomain"; break; case ApplicationShutdownReason.MaxRecompilationsReached: shutdownDetail = "The maximum number of dynamic recompiles of a resource limit was reached"; break; case ApplicationShutdownReason.PhysicalApplicationPathChanged: shutdownDetail = "A change was made to the physical path to the application"; break; case ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename: shutdownDetail = "A change was made to the App_GlobalResources foldr or the files contained within it"; break; case ApplicationShutdownReason.UnloadAppDomainCalled: shutdownDetail = "A call to UnloadAppDomain() was completed"; break; default: shutdownDetail = "Unknown shutdown reason"; break; }


Esta es una respuesta realmente tardía, pero espero que pueda proporcionar una perspectiva adicional para aquellos que tienen problemas similares (IIS 7.x o superior).

1. Averiguar cuándo el grupo de aplicaciones está comenzando a cerrarse : el siguiente código se puede usar para saber cuándo el grupo de aplicaciones inicia su cierre. El cierre real se produce en un límite máximo de cierre (segundos, valor predeterminado 90) después de este evento.

public class ApplicationPoolService : IApplicationPoolService { public bool IsShuttingDown() { return System.Web.Hosting.HostingEnvironment.ShutdownReason != ApplicationShutdownReason.None; } public ApplicationShutdownReason GetShutdownReason() { return System.Web.Hosting.HostingEnvironment.ShutdownReason; } } public class HostingEnvironmentRegisteredObject : IRegisteredObject { public void Stop(bool immediate) { // second call is done when the Stop is imminent if (immediate) return; var reason = appPoolService.GetShutdownReason().ToString(); logger.Log(LogLevel.Info, $"HostingEnvironmentRegisteredObject.stop called with shutdown reason {reason}"); } } // this code should be placed in global.asax.cs protected void Application_Start() { HostingEnvironment.RegisterObject(new HostingEnvironmentRegisteredObject()); }

Esto ayuda a encontrar la razón general y exactamente cuándo se activó. En su caso, creo que HostingEnvironment es el valor. Desafortunadamente, la causa subyacente no es única. Puede ser reciclar periódicamente, reciclar debido al límite de memoria (la razón más probable en la pregunta de OP), reciclar debido a una hora fija, etc.

2. Encontrar la causa exacta : una forma de averiguar la causa exacta es buscarla en el EventLog. Si esto no es accesible, se puede solicitar al proveedor de alojamiento al proporcionar los siguientes detalles para limitar su búsqueda.

  • Hora exacta de inicio de parada
  • Filtro de registro de eventos:
    • Fuentes de eventos = WAS
    • Nivel de evento = Información
    • Registrado = rango personalizado que incluye el tiempo exacto de apagado +/- 1 minuto más o menos

El registro de eventos debe devolver información más relevante como las siguientes:

Un proceso de trabajo con el ID de proceso de ''xxx'' que sirve al grupo de aplicaciones ''xxx'' ha solicitado un reciclaje porque alcanzó su tiempo de reciclaje programado.


Un proceso de trabajo con ID de proceso de ''xxx'' que sirve al grupo de aplicaciones ''xxx'' ha solicitado un reciclaje porque alcanzó su límite de memoria virtual.


Sin acceso a los registros de eventos (debido a que está en un entorno de alojamiento compartido), la mayor información que obtendrá es del evento Application_End y le pide a HttpRuntime (a través de la reflexión) los valores de uno o dos miembros privados que Lamentablemente no se exponen públicamente.

Para hacer esto, agregue el siguiente código a su evento Application_End :

BindingFlags staticFlags = BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField; BindingFlags instanceFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField; HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime) .InvokeMember("_theRuntime", staticFlags, null, null, null); if(runtime != null) { string shutDownMessage = (string)runtime.GetType() .InvokeMember("_shutDownMessage", instanceFlags, null, runtime, null); string shutDownStack = (string)runtime.GetType() .InvokeMember("_shutDownStack", instanceFlags, null, runtime, null); // Log shutDownMessage & shutDownStack somewhere }

Si apago o reciclo el grupo de aplicaciones de mi aplicación, veo lo siguiente:

HostingEnvironment initiated shutdown HostingEnvironment caused shutdown - at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace() at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal() at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand() at System.Web.Hosting.PipelineRuntime.StopProcessing()

Eso es probablemente tan bueno como se pone.

Actualizar:

No podía recordar dónde encontré este código, pero Drew me recordó que era de una publicación de Scott Guthrie.

Hay algunos otros miembros privados que podrían ser útiles, tales como:

private ApplicationShutdownReason _shutdownReason;

Puede examinar estos campos en .NET Reflector (si todavía tiene una copia que no está bombardeada) o una de las alternativas (¿ Alternativas de código abierto para Reflector? ).