example - remarks c#
¿Qué sucede en BeginProcessRequest()? (4)
Encontré este mismo problema en una aplicación que tenía un uso mínimo de sesiones. Después de tener en cuenta la respuesta aceptada e incluso de eliminar temporalmente SessionState por completo con fines de diagnóstico, todavía tenía problemas significativos con el rendimiento en este ''Método''.
Basándome en el comentario de todd_saylor en este hilo , investigué mucho en mi propio sitio y encontré que BeginProcessRequest
puede servir como el nuevo catch-all de New Relic para pérdidas de rendimiento misceláneas que aparecen en diferentes áreas de código. Pude reducir significativamente el tiempo en esta área, al crear un código de perfil en mi máquina local utilizando ANTs Performance Profiler de Red Gate.
Mi perfil local reveló algunas cosas:
- Estaba usando Ninject como mi contenedor DI, lo que causó la pérdida de rendimiento en su resolución de objeto. Lo reemplacé con SimpleInjector y aumenté el rendimiento en un orden de magnitud.
- Encontré que en algún lugar entre el
Project().To<>()
Extensiones IQueryable de AutoMapperProject().To<>()
y el proveedor del Servidor Sql de Linq, que la compilación dinámica y JITing de las proyecciones era responsable del 50% de mi tiempo de solicitud. Reemplazar eso con CompiledQuerys hizo otra mella significativa.
¡Espero que esto ayude a alguien más!
Estamos utilizando NewRelic para proporcionar rastreos de aplicaciones del lado del servidor.
Hemos notado que algunas de nuestras aplicaciones gastan de manera consistente aproximadamente 100 ms en el método System.Web.Mvc.MvcHandler.BeginProcessRequest()
.
Esto ocurre antes de que se llame a cualquier código de controlador personalizado (que se registra por separado, y no de forma acumulativa): no es obvio por qué se gastaría tanto tiempo en este método.
¿Qué tipo de cosas hará MVC en este método? ¿Podría esto simplemente solicitar cola?
[EDIT:] Como era de sospecha, la respuesta de Scalayer a continuación fue puntual. Eliminamos y optimizamos todas nuestras dependencias de sesión, y vimos un aumento masivo en la escalabilidad y estabilidad de la aplicación
Lo que puede estar viendo se conoce comúnmente como Agilidad de subprocesos en .NET.
Lo que probablemente esté viendo en cuanto a los resultados debajo de la etiqueta tópica (es decir, el código de la aplicación en System.Web.HttpApplication.BeginRequest()
) es un problema de agilidad de hilos; en la mayoría de los casos, el tiempo que ve aquí no es necesariamente el código que se está ejecutando, sino el contexto web que espera que los hilos se le vuelvan a liberar desde un bloqueo lector-escritor.
La "pausa" Application_BeginRequest()
es bastante común en una pila web de ASP.NET. En general, cuando ve tiempos de carga largos en BeginRequest, se trata de agilidad de subprocesos ASP.NET y / o bloqueos de subprocesos, especialmente cuando se trata de IO y operaciones basadas en sesiones. No es que sea malo, así es como .net se asegura de que tus hilos permanezcan concurrentes.
El intervalo de tiempo generalmente ocurre entre BeginRequest y PreRequestHandlerExecute. Si la aplicación está escribiendo varias cosas para la sesión, ASP.NET emitirá un bloqueo de lector-escritor en HttpContext.Current.Session
.
Una buena forma de ver si este es un problema que podría enfrentar sería verificar los ID de los hilos para ver si la agilidad es un problema: los ID serán diferentes para una solicitud determinada.
Por ejemplo. Mientras realiza la depuración, quizás podría agregar lo siguiente a su Global.asax.cs
:
protected void Application_BeginRequest(Object sender, EventArgs e) {
Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString());
}
Abra la ventana de salida de depuración (desde Visual Studio: Ver >> Salida, luego seleccione "Depurar" desde el menú desplegable "mostrar salida desde").
Mientras realiza la depuración, acceda a una página donde haya visto el tiempo prolongado. Luego, vea el registro de salida: si ve varios identificadores, es posible que sufra esto.
Esta es la razón por la que puede ver el retraso algunas veces, pero otras veces, el código de la aplicación podría estar usando la sesión de forma diferente o las operaciones de sesión o IO podrían ser mayores o menores de una página a otra.
Si este es el caso, puede hacer algunas cosas para ayudar a acelerar las cosas dependiendo de cómo se usa la sesión en el sitio o en cada página.
Para las páginas que no modifican la sesión:
<% @Page EnableSessionState="ReadOnly" %>
Para páginas que no usan estado de sesión:
<% @Page EnableSessionState="False" %>
Si la aplicación no usa session (web.config):
<configuration>
<system.web>
<sessionState mode="Off" />
</system.web>
</configuration>
Tomemos el siguiente ejemplo:
El usuario carga una página, luego decide ir a otra página antes de que la primera solicitud finalice. Al cargar ASP.NET, se forzará un bloqueo de sesión que causará que la nueva carga de solicitud de página espere hasta que finalice la primera solicitud de la página. Con ASP.NET MVC, cada acción bloquea la sesión del usuario para la sincronización; causando el mismo problema
Todo el tiempo necesario para que se libere la cerradura se informará a través de una nueva reliquia, por no mencionar aquellos en los que el usuario abandonó la sesión y el hilo que vuelve busca un usuario que ya no existe.
Por cierto, el control UpdatePanel causa el mismo comportamiento:
http://msdn.microsoft.com/en-us/magazine/cc163413.aspx
Qué se puede hacer:
Este problema de bloqueo es uno de los motivos por los que Microsoft tiene la clase SessionStateUtility:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
Para que pueda anular el comportamiento predeterminado si enfrenta este problema como se ve aquí en esta implementación de Redis: https://github.com/angieslist/AL-Redis
Hay muchas opciones para el proveedor de estado predeterminado utilizado por los sitios web basados en .net. Pero sepa en general que este tiempo de transacción indica que los hilos están siendo bloqueados y esperando que se completen las solicitudes al servidor.
Para cualquiera que esté leyendo esto y experimente un alto uso de la CPU de IIS que no tiene explicación, eche un vistazo a este hilo del foro de soporte de NewRelic que abrí.
He estado lidiando con este problema durante más de una semana, hasta que me di cuenta de que era su agente el origen del problema.
Agente .NET que causa un uso elevado de CPU en IIS
entonces, lo primero que sugiero que intente es eliminar el agente .NET y ver si hay algún cambio, antes de sumergirse en experimentos más complejos.
Publiqué esta respuesta sobre esta pregunta en particular porque llegué aquí primero mientras trabajaba en el tema, y la agilidad de la secuencia me puso en un curso largo que no era correcto ... (aunque muy interesante en sí mismo).
Si desea habilitar un determinado controlador para procesar solicitudes en paralelo desde un solo usuario, puede usar un atributo llamado SessionState que se introdujo en MVC desde la versión 3. No es necesario usar un controlador sin sesión para lograr el paralelismo. la opción Ready-only de SessionStateBehavior le permitirá pasar comprobaciones de seguridad que puede haber implementado en función de los datos de sesión.
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class ParallelController : Controller
{
...
}
También tuve retrasos en System.Web.Mvc.MvcHandler.BeginProcessRequest()
, cuando intento hacer algunas acciones largas y lo vi en NewRelic
. Estos atributos han resuelto el problema y le han permitido manejar acciones paralelas para este controlador.