¿Qué hacer si MSMQ tarda mucho en enviar el primer mensaje?

MSMQ es una de esas tecnologías que de repente reviven, y pasan de ser usadas por unos pocos a ser ampliamente utilizadas. WCF y la popularidad que las arquitecturas EDA (Event Driven Architecture) han ganado tiene que ver mucho con este renacer. WCF ha facilitado enormemente la utilización de MSMQ llevando las ventajas de las comunicaciones basada en mensajería a una infinidad de arquitecturas. Si queréis saber más sobre el tema no os perdáis un webcast muy interesante del que ya hablé hace un tiempo: Webcast: Patrones para arquitecturas orientadas a eventos y mensajes.

WCF pone una capa de abstracción sobre MSMQ que facilita enormemente su uso, pero que también dificulta en cierto modo la detección de problemas. No debemos olvidar que MSMQ esta debajo de WCF. Y todas las abstracciones fugan. Es en ese momento cuando tenemos que bajar de nivel y ver que pasa en MSMQ. Son muchos los aspectos de MSMQ que pueden penalizar el rendimiento o la estabilidad de nuestra aplicaciones, por mucho que WCF abstraiga los aspectos más truculentos. La fuente última de información sobre MSMQ una tecnología de Microsoft no muy bien documentada es un documento, de ciento y pico páginas, nada fácil del encontrar llamado Message Queuing Frequently Asked Questions. Regencia imprescindible para cualquiera que use MSMQ en sus aplicaciones.

Hoy voy a hablar de una de esas situaciones en que hay que trastear con los oscuros parámetros de MSMQ, un sniffer de red y los contadores de rendimiento para lograr que nuestra aplicación funcione como debe.

Hace unos días recibí una llamada de un cliente. Una aplicación que funcionaba perfectamente en decenas de instalaciones no se comportaba como debía. La primera vez que realizaban unas acciones (que yo sabía que implicaban el envío de un mensaje de MSMQ mediante WCF) la aplicación tardaba un motón de tiempo (alrededor de un minuto) en arrojar resultados. Esto era especialmente molesto, pues el patrón típico de uso de la aplicación era largos tiempos de inactividad seguidos de momentos en que debía responder rápidamente.

Una cosa que mucha gente desconoce de MSMQ es que trabaja mediante sesiones (ojo, no confundir con las sesiones de WCF, nada que ver). Siempre que en una arquitectura nos encontramos con ‘sesiones’ sean del tipo que sean, sabemos o podemos intuir dos cosas: que establecer esas sesiones tiene un coste y que las sesiones tienden a caducar tras ciertos periodos de inactividad para ahorrar recursos. Pues bien, esta es la clave del asunto que hoy nos preocupa: típicamente iniciar una sesión de MSMQ es un proceso que no debe llevar más de unos milisegundos. De todos modos es un proceso complejo que implica numerosos elementos de nuestra infraestructura de red y comunicaciones: consultas DNS, consultas al directorio activo, autenticación de usuarios y el intercambio de unos cuantos intercambios de información por la red. Podéis ver el proceso en la siguiente captura de red (realizada con Microsoft Network Monitor):

MSMQ Session

La parte resaltada en rojo, se corresponde con el establecimiento de la sesión de MSMQ. La parte resaltada en azul con el envío del primer mensaje. Si en alguno de los paquetes intercambiados hubiese un retardo relevante, con alta probabilidad, tendríamos un problema relacionado con la apertura de sesiones.

En esta situación, la solución pasa por ver que elementos de nuestra infraestructura subyacente está fallando. Más adelante comentaré algunas opciones para resolver esta cuestión, pero ahora voy a comentar un workarround rápido para el problema. Es evidente que una táctica que podemos usar, es evitar que las sesiones de MSMQ caduquen. Así solo pagaremos el peaje del retardo en una única ocasión. Para controlar el tiempo que tardan en caducar las sesiones de MSMQ hemos de modificar el valor CleanupInterval en la clave HKEY_LOCAL_MACHINESOFTWAREMicrosoftMSMQParameters que controla el tiempo de caducidad de las sesiones de MSMQ. Hay que resaltar, ya que la documentación no lo dice que debemos establecer este valor tanto en el cliente como en el servidor pues prima el menor de ambos (anda que no me dio quebraderos de cabeza este tema). El valor máximo es 0xffffffff milisegundos, unos cincuenta días.

MSMQ Session Cleanup Interval

Para monitorizar el comportamiento de las sesiones de MSMQ lo mejor es usar los contadores de rendimiento de MSMQ: 

MSMQ Sessions Performance Counter

Evidentemente este ‘workarround’ tiene efectos laterales:

1) Cada sesión abierta consume una CAL de servidor. Si agotamos esas CAL, sucesivos clientes no se podrán conectar. Además hay que recordar que en un sistema operativo que no sea de servidor como máximo podremos tener diez sesiones abiertas simultáneamente.
2) Mantener sesiones, consume recursos y puede afectar a la escalabilidad.

Evidentemente lo aquí comentado solo minimiza el problema pero no los resuelve. Algunas recomendaciones para diagnosticar este tipo de problemas son:

– Usar la IP del servidor a establecer la dirección de la cola remota. Nos ahorraremos la resolución de nombres y podemos diagnosticar si el retardo de establecimiento de sesione tiene que ver con esto.
– Usar colas privadas, sin autenticación y sin transaccionacionalidad. Nos ahorraremos consultas al AD para localizar las colas, para autenticar usuarios y nos ahorraremos mensajes de ACK de MSMQ para mantener la transaccionacionalidad.

¡Espero que os resulte interesante!

5 comentarios en “¿Qué hacer si MSMQ tarda mucho en enviar el primer mensaje?”

  1. Rodrigo, buen post, pero quedaría mucho mejor aún si trataras de explicar los condicionamientos de estas sesiones de MSMB con NLB y como podría afectar establecer un CleanupInterval con un tiempo elevado

  2. Otro detalle a tener en cuenta es no escribir y leer de manera indiscriminada en las colas remotas y locales. Conviene escribir en las colas remotas y leer de las colas locales, así se pueden evitar errores de COM y de licencias CAL.
    Saludos, PV

  3. @Unai:
    La pregunta es sumamente interesante. La verdad es que no sabía la respuesta, pero no estaba muy lejos. La he encontrado en el documento de FAQ de MSMQ que comento en el post. En un entorno NLB las sesiones tienen afinidad al nodo. Esto quiere decir que si modificamos la duración de las sesiones y ponemos un tiempo muy largo estamos perdiendo capacidad de balanceo de carga. Otra pega más del ‘workarround’ que comento en el post.

    @Javier:
    Jejejej… si si, no me extraña que te suene… la buena noticia es que por lo menos el problema ahora no molesta, aunque existe. Y en el caso particular que tu conoces, las pegas que tiene el ‘workarround’ no afectan.

    @Paulo:
    Buena apreciación. En el caso de usar WCF lo que comentas lo hace WCF por nosotros. Pero usando MSMQ directamente, la recomendación es la que tu comentas.

    ¡Gracias por vuestros comentarios!

  4. Lo mejor del post, sin desmerecer el resto, el documento de FAQ de MSMQ, no sabía que existía, pero es la biblia de MSMQ.

    ¡Muchas gracias!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *