Compartir a través de


Este artículo proviene de un motor de traducción automática.

Windows Azure Insider

Bus de servicio de Windows Azure: Patrones de mensajería mediante Sesiones

Bruno Terkaly
Ricardo Villalobos

Descargar el ejemplo de código

Bruno Terkaly Ricardo VillalobosEn uno de nuestros artículos anteriores, hablamos de la importancia de utilizar patrones de mensajes en la nube para desacoplar soluciones y arquitecturas de software fácil de escala de promover. (Ver "Comparación de Windows Azure y servicio Bus colas" en msdn.microsoft.com/magazine/jj159884.) Cola es uno de estos patrones de mensajes, y la plataforma de Windows Azure ofrece dos opciones principales para aplicar este enfoque: Servicios de almacenamiento de colas y colas de Bus de servicio, que cubren escenarios donde varios consumidores compiten para recibir y procesar cada uno de los mensajes de una cola. Este es el modelo canónico para soportar las cargas de trabajo variables en la nube, donde los receptores pueden dinámicamente añadir o quitar basado en el tamaño de la cola, ofreciendo un mecanismo de failover/balanceo de carga para el back-end (ver figura 1).

Queuing Messaging Pattern: Each Message Is Consumed by a Single Receiver
Figura 1 cola patrón de mensajería: Cada mensaje es consumido por un solo receptor

Aunque el patrón de mensajería cola es una gran solución para disociación simple, hay situaciones donde cada receptor requiere su propia copia del mensaje, con la opción de descartar algunos mensajes basados en reglas específicas. Un buen ejemplo de este tipo de escenario se muestra en figura 2, que ilustra un desafío común que retail empresas cara al enviar información a varias ramas, como el último catálogo de productos o una lista de precios actualizada.

Publisher/Subscriber Messaging Pattern: Each Message Can Be Consumed More Than Once
Figura 2 Editorial/suscriptor patrón de mensajería: Cada mensaje puede ser consumido por más de una vez

Para estas situaciones, el patrón de publisher o suscriptor es un mejor ajuste, donde los receptores simplemente expresan su interés en una o más categorías de mensajes, conectar a una suscripción independiente que contiene una copia de la secuencia del mensaje. El Bus de servicio de Windows Azure implementa el patrón de mensajería publisher o suscriptor a través de temas y suscripciones, que mejora en gran medida la capacidad para controlar cómo se distribuyen los mensajes, basándose en reglas independientes y filtros. En este artículo, explicaremos cómo aplicar estas capacidades de Bus de servicio de Windows Azure utilizando un simple escenario de vida real, asumiendo los siguientes requisitos:

  1. Productos deben recibirse en orden, basado en la página de catálogo.
  2. Algunas de las tiendas no llevan categorías catálogo específico, y productos en estas categorías deben ser filtrados para cada tienda.
  3. Nuevo catálogo de la información no debería aplicarse al sistema de almacén hasta que todos los mensajes han llegado.

Todos los ejemplos de código para este artículo fueron creados con Visual Studio 2012, utilizando C# como lenguaje de programación. También necesitará la versión 1.8 de Windows Azure SDK para desarrolladores .NET y acceso a una suscripción de Windows Azure.

Configurar el plan de mensajería para el proyecto

Antes de escribir ningún código, es necesario definir las diferentes entidades (temas y suscripciones) que pasarán a formar parte del flujo de trabajo de mensajería. Esto puede lograrse mediante el acceso al Portal de Windows Azure en manage.windowsazure.com. Iniciar sesión con sus credenciales y siga estos pasos:

  1. Haga clic en el icono Crear nueva en la parte inferior izquierda de la administración del Portal.
  2. Haga clic en el icono servicios de aplicación y luego en tema de autobús de servicio y finalmente en crear CUSTOM (ver figura 3).
  3. En la primera pantalla de diálogo, escriba el nombre del tema y seleccione el ID de suscripción correspondiente región y Windows Azure Si este es el primer espacio de nombres en la región seleccionada, el asistente le sugerirá una cola de espacio de nombres: [nombre entidad]-ns. Puede cambiar este valor.
  4. Haga clic en la siguiente marca (flecha hacia la derecha) para insertar el resto de propiedades. Usted puede guardar los valores predeterminados. Haga clic en la marca de verificación para crear el tema.
  5. Haga clic en el icono de servicio de autobús en la barra de navegación de la izquierda para obtener una lista de espacios de nombres. Tenga en cuenta que puede que no vea el espacio de nombres aparecen inmediatamente. Tarda unos segundos para crear el espacio de nombres y actualizar la interfaz de portal.
  6. Seleccione el tema que acaba de crear en la lista y haga clic en la clave de acceso, que se encuentra en la parte inferior de la pantalla. Registro de la cadena de conexión completa para su uso posterior.
  7. En la parte superior de la pantalla de Windows Azure Portal, haga clic en las suscripciones y luego en crear una nueva suscripción. En el cuadro de diálogo emergente, escriba un nombre (en nuestro ejemplo, usamos "Store1Sub") y haga clic en la flecha para continuar.
  8. En la siguiente pantalla, mantenga los valores predeterminados, pero asegúrese de activar la opción de habilitar sesiones. Haga clic en la marca para crear la suscripción. Las sesiones se utilizará por los suscriptores para recuperar los mensajes en orden secuencial.
  9. Repita los pasos 7 y 8 para cada uno de los tres almacenes.

Creating a New Service Bus Topic Using the Windows Azure Portal
Figura 3 creación de un nuevo tema de autobús de servicio utilizando el Windows Azure Portal

Una vez que se han creado los temas y las suscripciones, también se puede acceder directamente en Visual Studio. Para ello, abra el explorador de servidores (vista | Explorador de servidores) y expanda el nodo Windows Azure Service Bus (ver figura 4). Haga clic derecho en el nodo de Windows Azure Service Bus y seleccione Agregar nueva conexión. Escriba el nombre del Namespace, nombre del emisor (generalmente "propietario") y clave de acceso emisor registró cuando el espacio de nombres de Windows Azure se creó en el portal.

Creating a Service Bus Topic and Subscriptions Using the Visual Studio Tools
Figura 4 crear un tema de autobús de servicio y suscripciones mediante Visual Studio Tools

Tenga en cuenta que es posible crear y administrar estas entidades mediante clases en el espacio de nombres Microsoft.ServiceBus.Messaging, TopicClient y SubscriptionClient, que se utilizan más adelante en este artículo mediante programación.

Una vez que se ha creado la estructura básica para el flujo de trabajo de mensajería, podrá simular el tráfico mediante dos aplicaciones de consola creadas en Visual Studio, como se muestra en figura 5. La primera aplicación de consola, MSDNSender, enviaremos el catálogo de productos. La segunda, MSDN­receptor, recibirá la información en cada una de las tiendas. Analizaremos el código en las secciones siguientes. En el modelo Pub/Sub, el MSDNSender es el editor y el MSDNReceiver es el suscriptor.

Visual Studio Solution to Simulate the Products Catalog Scenario
Figura 5 solución de Visual Studio para simular el escenario del catálogo de productos

Enviar el catálogo de productos de la sede

Como se puede ver en figura 2, sede (la editorial) envía mensajes a un tema. Esta lógica es representada por el código en el archivo principal, Program.cs, una parte del proyecto MSDNSender. Program.CS encapsula la lógica y el código para enviar una lista de productos como mensajes individuales al tema. Echemos un vistazo a las diferentes secciones, comenzando con el método Main. Tenga en cuenta que primero creamos un cliente para el tema, como sigue:

 

// Create a topicClient using the
// Service Bus credentials
TopicClient topicClient =
  TopicClient.CreateFromConnectionString(
  serviceBusConnectionString, topicName);

Una vez creado un topicClient, el editor puede enviar mensajes de usarlo. La lista de productos a ser enviados se almacena en un archivo XML denominado ProductsCatalog.xml, que contiene una lista de 10 entidades de producto que se transformará en una matriz de objetos. Luego haz se asignan los productos en las clases de catálogo y productos almacenadas en el archivo Product.cs:

// Deserialize XML file with Products, and store them in an object array
Catalog catalog = null;
string path = "ProductsCatalog.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
StreamReader reader = new StreamReader(path);
catalog = (Catalog) serializer.Deserialize(reader);
reader.Close();

Cada producto en la matriz de catálogo presenta la estructura que se muestra en la figura 6.

Figura 6 representación de clase de productos en el catálogo

public class Product
  {
    [System.Xml.Serialization.XmlElement("ProductId")]
    public string ProductId { get; set; }
    [System.Xml.Serialization.XmlElement("ProductName")]
    public string ProductName { get; set; }
    [System.Xml.Serialization.XmlElement("Category")]
    public string Category { get; set; }
    [System.Xml.Serialization.XmlElement("CatalogPage")]
    public int CatalogPage { get; set; }
    [System.Xml.Serialization.XmlElement("MSRP")]
    public double MSRP { get; set; }
    [System.Xml.Serialization.XmlElement("Store")]
    public string Store { get; set; }
  }

Dentro del bucle de la matriz, una llamada al método CreateMessage extrae diferentes propiedades de los objetos del producto y las asigna a enviar el mensaje. Dos propiedades requieren atención adicional:

if (isLastProductInArray)
  message.Properties.Add("IsLastMessageInSession", "true");
message.SessionId = catalogName;

Las sesiones son extremadamente importantes, porque permiten que el receptor para determinar si han llegado todos los mensajes que pertenecen a un grupo específico de la lógico. En este caso, estableciendo la propiedad de mensaje SessionId, especificamos que el receptor no debe utilizar la información del catálogo hasta después de han llegado todos los mensajes con el mismo valor de catalogName. También, para el último producto de la matriz, estamos agregando una nueva propiedad: IsLastMessageInSession, que permite a los receptores determinar si ha llegado el último mensaje en la sesión, y el catálogo se pueden procesar completamente. Figura 7 muestra MSDNSender funcionando.

Execution of the MSDNSender Project
Figura 7 ejecución del proyecto MSDNSender

Recibir el catálogo de productos mediante suscripciones en las tiendas

Ahora que el catálogo y los productos han sido enviados al tema y copia en las diferentes suscripciones, vamos a centrar nuestra atención en el proyecto de MSDNReceiver, donde se reciben y procesan los mensajes. Tenga en cuenta que en el método Main de Program.cs, el código crea un cliente para la suscripción basado en información proporcionada por el usuario a través de un Console.Read­línea de comando. Los usuarios deben anotar su número de tienda, que refleja los mensajes que desea recibir. En definitiva, cada sucursal se refiere únicamente a los mensajes que se aplican a esa tienda:

Console.WriteLine("Enter Store Number");
  string storeNumber = Console.ReadLine();
  Console.WriteLine("Selecting Subscription for Store...");
  // Create a Subscription Client to the Topic
  SubscriptionClient subscriptionClient =
    SubscriptionClient.CreateFromConnectionString(
    serviceBusConnectionString, topicName,
    "Store" + storeNumber.Trim() + "Sub",
    ReceiveMode.PeekLock);

Porque nosotros estamos recibiendo mensajes de las suscripciones de sesiones (como se explica en la sección anterior), tenemos que solicitar la siguiente con la siguiente línea de código:

MessageSession sessionReceiver =
  subscriptionClient.AcceptMessageSession(TimeSpan.FromSeconds(5));

Básicamente, lo que esto significa es que el cliente buscará los mensajes para ser procesados en la suscripción — aquellos cuya propiedad SessionId no es nulo, y si no hay este tipo de mensajes se encuentra dentro de un período de cinco segundos, el tiempo de la solicitud ­hacia fuera, terminar la aplicación del receptor. Por otro lado, si se encuentra una sesión, se llamará al método ReceivingSessionMessages. Antes de saltar en este fragmento de código, vamos a discutir el concepto de estado de sesión, que permite al desarrollador almacenar información que puede utilizarse mientras se reciben mensajes que pertenecen a la misma transacción. En este caso, estamos utilizando el estado de sesión para "recordar" la última página de catálogo que se recibió, así como los mensajes — productos — que llegó fuera de orden.

Basados en esto, aquí está el flujo de trabajo en código:

  1. El mensaje actual en la ReceiveSession­método de mensajes (ver figura 8), que se basa en el método ProcessMessage (figura 9) para procesarlo.
  2. Dentro del método ProcessMessage, si el mensaje fuera de secuencia, automáticamente se ha aplazado y su identificador se almacena en el estado de sesión. De lo contrario, tiene marcado como "completo" y quitar de la suscripción. Espera también, la siguiente secuencia: página Catálogo — se almacena en el período de sesiones.
  3. Después de procesar el mensaje recibido, el código posterior ReceiveSessionMessages busca mensajes diferidos IDs en el período de sesiones e intenta procesar nuevamente en base a la última página del catálogo.
  4. Una vez recibidos todos los mensajes de la sesión, se cierra el receptor.

Figura 8 el método ReceivedSessionMessages en el código

static void ReceiveSessionMessages(MessageSession receiver)
  {
    // Read messages from subscription until subscription is empty
    Console.WriteLine("Reading messages from subscription {0}", 
      receiver.Path);
    Console.WriteLine("Receiver Type:" + receiver.GetType().Name);
    Console.WriteLine("Receiver.SessionId = " + receiver.SessionId);
    SequenceState sessionState = GetState(receiver);
    BrokeredMessage receivedMessage;
    while ((receivedMessage = receiver.Receive()) != null)
    {
      string sessionId = receiver.SessionId;
      ProcessMessage(receivedMessage, ref sessionState, receiver);
      while (sessionState.GetNextOutOfSequenceMessage() != -1)
      {
        // Call back deferred messages
        Console.WriteLine("Calling back for deferred message: Category {0},
          Message sequence {1}", receiver.SessionId,
            sessionState.GetNextSequenceId());
        receivedMessage = receiver.Receive(
          sessionState.GetNextOutOfSequenceMessage());
        ProcessMessage(receivedMessage, ref sessionState, receiver);
      }
      if (receivedMessage.Properties.ContainsKey(
        "IsLastMessageInSession"))
        break;
    }
    SetState(receiver, null);
    receiver.Close();
  }

Figura 9 el método ProcessMessage en código

static void ProcessMessage(BrokeredMessage message, ref SequenceState sessionState,
  MessageSession session = null)
  {
    if (session != null)
    {
      int messageId = Convert.ToInt32(message.Properties["CatalogPage"]);
      if (sessionState.GetNextSequenceId() == messageId)
      {
        OutputMessageInfo("RECV: ", message, "State: " + "RECEIVED");
        sessionState.SetNextSequenceId(messageId + 1);
        message.Complete();
        SetState(session, sessionState);
      }
      else
      {
        Console.WriteLine("Deferring message: Category {0}, Catalog Page {1}",
          session.SessionId, messageId);
        sessionState.AddOutOfSequenceMessage(messageId, 
          message.SequenceNumber);
        message.Defer();
        SetState(session, sessionState);
      }
    }
    Thread.Sleep(receiverDelay);
  }

Tenga en cuenta que para este proyecto, ID de mensaje diferido se almacena en el estado de sesión y podría ser potencialmente perdidos. En un entorno de producción, se recomienda utilizar algún tipo de almacenamiento persistente (tablas de Windows Azure es una opción) para este propósito. Tenga en cuenta que si el mensaje contiene la propiedad IsLastMessage­SessionInSession (configurar durante el proceso envío), se termina el bucle de la sesión. La consola de salida para el proyecto de MSDNReceiver puede verse en figura 10.

Execution of the MSDNReceiver project
Figura 10 ejecución del proyecto MSDNReceiver

Suscripciones de Windows Azure Service Bus dan la capacidad de crear normas específicas que filtran los mensajes antes de que ellos son consumidos. En este caso, sería relativamente fácil crear una regla que segrega productos por categoría o por número de tienda (que omite en este proyecto). Las reglas se pueden crear mediante programación, directamente en el portal de Windows Azure o a través de herramientas de Visual Studio.

En resumen

El Bus de servicio de Windows Azure ofrece una implementación sorprendentemente robusta y flexible del patrón de publicación/suscripción. Muchos escenarios diferentes pueden abordarse mediante el uso de temas y suscripciones. La capacidad para soportar múltiples remitentes emitir mensajes a varios receptores, combinados con la capacidad de mensajes lógicamente grupo y tipo, abre un mundo de posibilidades para el desarrollo moderno. Por otra parte, poder aprovechar una sesión persistente para rastrear el Estado hace sencillo agrupar mensajes y controlar su secuencia lógica. En un mundo donde los entornos distribuidos son la norma, entender cómo utilizar patrones de mensajes y las herramientas a su alrededor es crucial para arquitectos de software de hoy trabajando en la nube.

Bruno Terkaly es un evangelista de desarrollador de Microsoft. Su profundidad de conocimiento proviene de años de experiencia en el campo, escribir código con una multitud de plataformas, idiomas, marcos, SDK, bibliotecas y APIs. Pasa la escritura de código de tiempo, blogging y dando presentaciones en vivo en la construcción de aplicaciones basadas en la nube, específicamente con la plataforma Windows Azure.

Ricardo Villalobos es un arquitecto de software experimentados con más de 15 años de experiencia en diseño y creación de aplicaciones para empresas en la industria de administración de la cadena de suministro. Sostiene diferentes certificaciones técnicas, así como una Maestría en administración de empresas de la Universidad de Dallas, trabaja como arquitecto de cloud en el grupo de incubación de Windows Azure CSV para Microsoft.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Abhishek Lal