Las extensiones personalizadas de WCF fuerzan a las operaciones simultáneas a ejecutarse secuencialmente
En este artículo se describe que puede experimentar tiempos de espera de cliente o períodos de latencia largos porque las extensiones personalizadas de WCF fuerzan las operaciones simultáneas a ejecutarse secuencialmente y proporciona una resolución.
Versión del producto original: Microsoft .NET Framework 4.5
Número KB original: 2907010
Síntomas
Imagine la siguiente situación:
Tiene el servicio Windows Communication Foundation (WCF) configurado para administrar varias solicitudes simultáneas.
Tiene implementaciones personalizadas de cualquiera de las siguientes extensiones WCF:
ServiceAuthenticationManagerServiceAuthorizationManagerIDispatchMessageInspectorIDispatchOperationSelector
Estas implementaciones son costosas computacionalmente, o en ocasiones incurren en períodos de latencia largos.
Las operaciones de servicio simultáneas parecen ejecutarse secuencialmente o los clientes tienen tiempo de espera.
Si ha experimentado tiempos de espera de cliente o tiempos de respuesta largos que parecen no estar relacionados con la carga del servidor en este escenario, puede que esté usando estas extensiones personalizadas de WCF de una manera que desencadene este problema.
Además, puede experimentar una situación en la que una solicitud retrasa otras solicitudes. A continuación, muchas solicitudes pueden finalizar repentinamente antes de que otra solicitud vuelva a retrasar otras solicitudes. Puede ver este comportamiento mediante el contador ServiceModelService Llamadas por segundo en el Monitor de rendimiento. Cuando se produce este comportamiento, el recuento puede bajar a cero mientras se ejecuta el código de extensión, incluso con varias solicitudes simultáneas pendientes. Cuando el código de extensión devuelve el control a WCF, el contador vuelve a su nivel típico hasta que el siguiente retraso en el código de extensión lo coloca de nuevo en cero.
Causa
Este problema se produce porque WCF invoca estos puntos de extensibilidad específicos de forma sincrónica, al principio de la canalización de control de mensajes. Los retrasos en estos puntos de extensibilidad pueden bloquear esa canalización. Esto evita la ejecución simultánea de operaciones de servicio. Los mensajes que se reciben durante este tiempo se ponen en cola pero no se atendidas hasta después de que esos puntos de extensibilidad devuelvan el control a WCF.
Esto hace que las operaciones de servicio se ejecuten de una en una, no al mismo tiempo. Cada solicitud espera en línea para que la anterior termine de ejecutar esos puntos de extensibilidad. Si la latencia es lo suficientemente alta, las solicitudes más recientes pueden dar tiempo de espera mientras esperan a que finalicen las solicitudes anteriores.
Estos son los métodos de extensibilidad específicos que se ven afectados:
- Microsoft .NET Framework 4.5 y .NET Framework 4.0:
ServiceAuthenticationManager.Authenticate()
- .NET Framework .NET Framework 4.5, .NET Framework 4.0, .NET Framework 3.5 y .NET Framework 3.0:
ServiceAuthorizationManager.CheckAccessCore()IDispatchMessageFormatter.AfterReceiveRequest()IDispatchOperationSelector.SelectOperation()
Solución
Para resolver este problema, use uno de los métodos siguientes:
- Minimice la latencia de estos puntos de extensibilidad.
- Mueva la sobrecarga de alta latencia a otro lugar de la canalización.
- Use un enlace WCF diferente.
Existen algunas prácticas comunes que pueden provocar una latencia alta desde estos puntos de extensibilidad:
- Acceso a una base de datos, especialmente en otro nivel
- Invocar otros servicios en otro nivel
- Uso de un gran volumen de memoria o subprocesos
- Hacer un trabajo costoso computacional
Si este trabajo de latencia alta es necesario, debe salir de estos puntos de extensibilidad. Por ejemplo, si este trabajo se realiza dentro de la propia operación de servicio, permitirá que se ejecuten varias operaciones al mismo tiempo.
Este comportamiento también puede depender de las capacidades del enlace que se usa para el extremo. Por ejemplo, BasicHttpBinding muestra este comportamiento, mientras que WsHttpBinding no lo hace.