Son posibles problemas de concurrencia cuando se utiliza el atributo de comportamiento del servicio WCF establecido en ConcurrencyMode.Multiple and InstanceContextMode.¿PerCall?


Tenemos un servicio WCF que hace una buena cantidad de llamadas NHibernate transaccionales. De vez en cuando estábamos viendo tiempos de espera SQL, a pesar de que las llamadas estaban actualizando diferentes filas y las tablas se establecieron en el bloqueo de nivel de fila.

Después de cavar en los registros, parece que diferentes hilos estaban ingresando el mismo punto en el código (nuestra transacción usando bloque), y una actualización estaba colgando en la confirmación. Sin embargo, no tenía sentido, porque creíamos que la siguiente clase de servicio el atributo estaba forzando un subproceso de ejecución único por llamada de servicio:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]

Recientemente cambiamos el modo de concurrencia a ConcurrencyMode.Single y aún no hemos tenido ningún problema, pero el error fue muy difícil de reproducir (si alguien tiene alguna idea sobre eliminar un error como ese, házmelo saber!).

De todos modos, todo eso me lleva a mi pregunta: ¿no debería un InstanceContextMode de PerCall imponer la seguridad de subprocesos dentro del servicio, incluso si el ConcurrencyMode se establece en múltiple? ¿Cómo sería ¿es posible que dos llamadas sean atendidas por la misma instancia de servicio?

Gracias!

Author: Brandon Linton, 2010-03-30

4 answers

La única manera de tener dos clientes WCF diferentes, es decir, proxies, que hagan referencia a la misma instancia de su servicio WCF es usar InstanceContextMode=InstanceContextMode.Single. Esta es una mala opción si el escalado es un problema, por lo que desea usar PerCall si puede.

Cuando se usa PerCall, cada LLAMADA al servicio WCF obtiene su propia instancia de servicio WCF. No se comparte la instancia de servicio, pero eso no significa que no compartan el mismo almacenamiento de back-end (por ejemplo, base de datos, memoria, archivo, etc.).). Solo recuerde, PerCall permite cada llamar para acceder a su servicio WCF simultáneamente.

El ConcurrencyMode la configuración controla el modelo de roscado del propio servicio. Una configuración de Single restringe todas las instancias de servicio WCF a ejecutarse en el mismo subproceso. Por lo tanto, si tiene varios clientes conectados al mismo tiempo, solo se ejecutarán uno a la vez en el lado del servicio WCF. En este caso, puede aprovechar WCF para proporcionar sincronización. Funcionará bien, como ha visto, pero piense en esto como tener solo control a nivel macro sobre la sincronización: cada llamada al servicio WCF se ejecutará en su totalidad antes de que la siguiente llamada se pueda ejecutar.

Establecer ConcurrencyMode a Multiple, sin embargo, permitirá que todas las instancias de servicio WCF se ejecuten simultáneamente. En este caso, usted es responsable de proporcionar la sincronización necesaria. Piense en esto como tener control de nivel micro sobre la sincronización, ya que solo puede sincronizar aquellos porciones de cada llamada que necesitan ser sincronizadas.

Espero haber explicado esto lo suficientemente bien, pero aquí hay un fragmento de la documentación de MSDN para ConcurrencyMode por si acaso:

Establecer ConcurrencyMode en Single indica al sistema que restrinja instancias del servicio a un hilo de ejecución en un momento, que libera usted de tratar con el enhebrado cuestión. Un valor de Múltiple significa que los objetos de servicio se pueden ejecutar mediante múltiples hilos en cualquiera tiempo. En en este caso, debe asegurarse de hilo seguridad.

EDITAR

Usted preguntó

¿Hay algún aumento de rendimiento, entonces, utilizando PerCall vs.Single cuando se utiliza ConcurrencyMode.¿Soltero? ¿O es verdad lo inverso?

Esto probablemente dependerá del servicio.

Con InstanceContextMode.PerCall, se crea una nueva instancia de servicio para cada llamada a través del proxy, por lo que tiene que lidiar con la sobrecarga de creación de instancias. Asumiendo su service constructor no hace mucho, esto no será un problema.

Con InstanceContextMode.Single, solo existe una instancia de servicio durante la vida útil de la aplicación, por lo que prácticamente no hay sobrecarga asociada con la creación de instancias. Sin embargo, este modo permite que solo una instancia de servicio procese cada llamada que se realice. Por lo tanto, si tiene varias llamadas que se realizan simultáneamente, cada llamada tendrá que esperar a que las otras terminen antes de que se pueda ejecutar.

Para qué vale la pena, así es como lo he hecho. Utilice el contexto de instancia PerCall con Multiple concurrencia. Dentro de su clase de servicio WCF, cree miembros estáticos para administrar el almacén de datos de back-end por usted, y luego sincronice el acceso a estos miembros estáticos según sea necesario usando la instrucción lock, los campos volatile, etc. Esto le permite a su servicio escalar muy bien mientras mantiene la seguridad del hilo.

 24
Author: Matt Davis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-26 16:24:27

Creo que la respuesta es el hecho de que hay múltiples subprocesos (en el lado del cliente) que utilizan la misma instancia de proxy, lo que potencialmente permite múltiples llamadas en la misma instancia. Este post tiene una explicación más detallada.

 7
Author: Kwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-30 15:13:29

InstanceContextMode.PerCall y ConcurrencyMode.Single debería estar bien si no está utilizando devoluciones de llamada de dos vías en el servidor. En ese caso, necesitará usar ConcurrencyMode.Reentrant o callback no podrá obtener acceso a la instancia de servicio bloqueada y se producirá un bloqueo.

Dado que es una creación de instancia de servicio por llamada, es imposible que otros subprocesos o llamadas obtengan acceso a ella. Como se indica en el artículo mencionado en otras respuestas artículo tal combinación todavía puede ser un problema si la sesión se crea en un nivel vinculante Y está utilizando el mismo objeto proxy de servicio.

Así que si no usa el mismo objeto proxy o no tiene un enlace sessionful y no usa devoluciones de llamada bidireccionales al cliente ( lo más probable es que sean OneWay de todos modos) InstanceContextMode.PerCall y ConcurrencyMode.Single debería ser bueno.

 2
Author: Valentin Kuzub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-19 07:12:55

Creo que todo depende del requisito. Si vamos a llamar al mismo servicio tantas veces entonces mejor podemos utilizar InstanceContextMode es Único y concurrencymode es múltiple.

 1
Author: Dayakar D.N,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-01 06:52:17