5

Necesito establecer una comunicación bidireccional entre un publicador y un suscriptor. Esto es para facilitar una aplicación front-end MVC3 que define una suscripción con un filtro de correlación, y luego colocar un mensaje en un tema. Finalmente, el controlador MVC3 llama a BeginReceive() en el Cliente de suscripción, y espera la respuesta.Azure Service Bus - Desafío de rendimiento de comunicación bidireccional

El problema parece ser la creación y eliminación de estos objetos de Suscripción. La sobrecarga es enorme y ralentiza la aplicación a paso de tortuga. Esto sin mencionar las diversas limitaciones para evitar, como no más de 2000 Suscripciones en un tema.

¿Cuál es la mejor práctica para establecer este tipo de comunicación bidireccional entre un publicador y un suscriptor? Queremos que la aplicación MVC3 publique un mensaje y luego espere una respuesta a ese mensaje exacto (a través de la propiedad CorrelationId y un CorrelationFilter). Ya almacenamos en caché NamespaceManager y MessagingFactory, ya que también son prohibitivamente caros, en cuanto a los recursos, y también porque se nos avisó que Service Bus utiliza un modelo de aprovisionamiento explícito, donde se espera precrear la mayoría de estas cosas durante el inicio del rol.

Por lo tanto, esto nos deja con el desafío de correlacionar la solicitud a la respuesta, y tener esta gran sobrecarga de la creación y eliminación de Suscripciones. ¿Qué mejor práctica existe? ¿Deberíamos mantener un caché de SubscriptionClients e intercambiar el filtro cada vez? ¿Qué hacen todos los demás? Necesito tener un rendimiento de solicitudes del orden de 5 a 10 mil solicitudes de MVC3 por segundo a través del clúster de roles web. Ya estamos usando AsyncController y empleando el BeginReceive asincrónico() en SubscriptionClient. Parece ser la creación y eliminación de las Suscripciones por miles lo que está estrangulando el sistema en este punto.

Update1: Basado en el gran consejo aquí proporcionada, hemos actualizado esta solución para mantener una caché de objetos SubscriptionClient en cada instancia de rol web. Además, hemos migrado a un enfoque orientado a MessageSession.

Sin embargo, esto todavía no está escalando. Parece que AcceptMessageSession() es una operación muy costosa. ¿Deberían los objetos MessageSession también almacenarse en caché y reutilizarse? ¿Cada objeto abierto MessageSession consume una conexión al Bus de servicio? Si es así, ¿esto se cuenta en contra de la cuota de conexión simultánea de la Suscripción?

Muchas gracias. Creo que estamos llegando. La mayor parte del código de ejemplo en la web muestra: Create Topic(), luego CreateSubscription(), luego CreateSubscriptionClient(), luego BeginReceive() en el cliente, luego el desmontaje de todos los objetos. Todo lo que puedo decir es que si hicieras esto en la vida real, tu servidor quedaría aplastado y maximizarías las conexiones en poco tiempo.

Tenemos que poner miles de solicitudes por segundo a través de esta cosa, y es muy evidente que estos objetos deben almacenarse en caché y reutilizarse en gran medida. Entonces, ¿MessageSession es otro elemento para caché? Me divertiré almacenando en caché eso, porque tendremos que implementar un mecanismo de recuento de referencias, donde solo se puede dar una referencia a MessageSession a la vez, ya que esto es para solicitud/respuesta específica de solicitud http, y no podemos tener otra suscriptores que usan los objetos MessageSession al mismo tiempo.

Update2: OK, no es factible MessageSession caché para su reutilización, ya que sólo viven tanto como el LockDuration en la suscripción. Esto es un fastidio, porque el LockDuration máximo es de 5 minutos. Estos parecen ser para pub/sub de corta duración, no para procesos distribuidos de larga ejecución. Parece que tenemos que volver a sondear Azure Tables.

RESUMEN/COMENTARIO Nos trató de construir el servicio de autobuses debido a la escala potencial y su semántica de durabilidad y entrega. Sin embargo, parece que hay situaciones, solicitudes/respuestas de alto volumen entre ellas, que no son adecuadas. La parte de publicación funciona muy bien, y tener consumidores que compiten en el back-end es excelente, pero tener una solicitud de front-end esperar en una respuesta definida de consumidor único, no se escala bien, porque las MessageSessions toman demasiado tiempo para crear a través de AcceptMessageSession() o BeginAcceptMessageSession(), y porque no son adecuados para el almacenamiento en caché.

Si alguien tiene una vista alternativa, me encantaría escucharla.

+1

Suena como algo en lo que ZeroMQ es bueno. http://www.zeromq.org/ –

+0

Gracias por el enlace. Eso se ve muy interesante. –

+0

OK, es una pregunta muy antigua, pero veo que ahora hay un método 'RenewLock' en las sesiones, así que tal vez ahora sean almacenables. –

Respuesta

4

Este escenario es una solicitud/respuesta clásica y un buen candidato para usar sesiones. Estos son otro mecanismo de correlación. Haga una cola de solicitud simple y una cola de respuesta. Cada subproceso de rol web crea un sessionid único para una solicitud y pone ese valor en la propiedad "ReplyToSessionID" del mensaje brokeredmessage. Además, este hilo llama a AcceptMessageSession en la cola de respuesta con el valor de sesión para que lo bloquee. El mensaje intermediario se envía a la cola de solicitudes y todas las funciones de los trabajadores compiten por los mensajes. Cuando una función de trabajador obtiene una solicitud, la procesa, crea un mensaje de respuesta y establece la propiedad de sesión en el mensaje de respuesta = respuesta de la solicitud. esto luego se envía a la cola de respuesta y solo se entregará al hilo que ha bloqueado esa identificación de la sesión. Una muestra detallada using sessions is here. Hay 2 muestras adicionales aquí usando Queues y Topics para lograr la correlación de respuesta de solicitud.

+0

¡Gracias! Esto es excelente, y fue el "Eslabón perdido" que necesitaba. ¿Ya no necesitaría los filtros de correlación en este caso? Parece que simplemente puedo usar Sesiones sin tener en cuenta el ID de Correlación ahora. –

+0

Implementé esto, primero en forma de bloqueo, con SubscriptionClient.AcceptMessageSession(). El rendimiento de eso es inaceptable, ya que parece agotar los hilos IIS. Entonces, pasé a SubscriptionClient.BeginAcceptMessageSession(). El problema ahora es que, en mi método de devolución de llamada, el parámetro IAsyncResult pasado es mi SubscriptionClient, por lo que puedo llamar a EndAcceptMessageSession(). El mayor desafío es que, a diferencia de AcceptMessageSession(), que devuelve MessageSession, MessageSession no está disponible. No está en AsyncManager.Parameters, cuyo recuento es 0, ni en ningún otro lado. –

+0

Async Call: subClient.BeginAcceptMessageSession (sessionId, TimeSpan.FromSeconds (30), (ar) => {ProcessAcceptMessageSession (ar);}, subClient); NOTA: Dentro de ProcessAcceptMessageSession (ar), no puedo encontrar la sesión en ningún lado en el alcance, y la documentación es escasa. –

1

Para un solo emisor y receptor solo necesita tener un solo tema/suscripción. Puede configurar varios correlation filters en la misma suscripción y así tener todas las respuestas que necesita correlacionadas aparecer en la misma suscripción. Actualmente admitimos hasta 100,000 instancias de filtro de correlación en una sola suscripción y estas se pueden agregar/eliminar (con transacciones si es necesario) junto con las operaciones de envío/recepción de mensajes sobre el tema/suscripción.

Además, puede usar Reglas con acciones para sellar el mensaje con propiedades adicionales si es necesario según el filtro que coincida.

+0

¿Qué ocurre con una situación con 12 instancias en Web Role (Publisher) y 6 instancias en un Rol de trabajador (Suscriptor)? Necesitamos que cada solicitud web se afilie fácilmente a su respuesta correlacionada. ¿Qué sucede cuando una instancia web coloca un mensaje en el bus de servicio, etiquetado con un Id de correlación, que el suscriptor usa para etiquetar el mensaje de respuesta?¿Cómo puede un hilo individual del front-end web recibir la respuesta correlacionada? Si The Topic enruta todas las coincidencias a la Suscripción, ¿no recibiría una llamada a BeginReceive() solo alguno de los mensajes correlacionados, en lugar de uno específico? –

1

Un enfoque alternativo es realizar una correlación de mensajes en la instancia de rol web utilizando un diccionario de id. De correlación y delegados de devolución de llamada.

Cada instancia de rol web (editor) tiene una sola suscripción, filtrada por una única ID de suscripción, al tema de respuesta.

Antes de enviar un mensaje, la devolución de llamada para ese mensaje se registra en el diccionario con la identificación de correlación como la clave. La ID de correlación y una ID de suscripción se envían junto con el mensaje de modo que la respuesta se pueda enviar de vuelta a la suscripción correcta junto con la ID de correlación.

Cada instancia de rol web supervisa la suscripción única y al recibir la respuesta elimina la entrada del diccionario e invoca la devolución de llamada.

+0

Gracias. ¿Puede darnos una idea de cómo funcionaría en un AsyncController en MVC3? No podría usar SubscriptionClient.Receive(), porque bloqueará el hilo de IIS, así que uso SubscriptionClient.BeginReceive() en su lugar. Proporciono una función de devolución de llamada para BeginReceive(), y se invoca cuando la recepción asíncrona recibe un mensaje o se agota el tiempo de espera. No entiendo cómo, cuando recibo el mensaje de EndReceive(), por qué iba a ejecutar otra devolución de llamada, y cómo se afiliaría a la solicitud original en IIS, ya que IIS simplemente toma cualquier hilo viejo para repararlo, a menos que yo llamar a Sync(). –

+0

Entonces, ¿cuál sería el propósito de la devolución de llamada en el diccionario? Esa es la conexión que no puedo hacer en este momento en mi mente. –

+0

El cliente de suscripción recibiría mensajes en su propio hilo y después de buscar el ID de correlación en el diccionario, invocar la devolución de llamada al hilo IIS en espera. Así liberando el hilo de IIS en espera y proporcionándole la respuesta. – hocho

Cuestiones relacionadas