O Simple Message Queue (SMQ, anteriormente MNS) oferece suporte a um padrão combinado de tópico e fila: um tópico distribui cada mensagem publicada para várias filas via push, e os consumidores recuperam as mensagens de suas próprias filas privadas por pull. Este tutorial implementa essa arquitetura de distribuição (fan-out) usando o SDK do SMQ para Java.
Este tutorial utiliza o SDK para Java. Para SDKs em outras linguagens, consulte Referência para SDKs da Nova Versão (Recomendado).
Comparação de modelos de mensagens
O SMQ fornece dois modelos básicos de mensagens. A escolha ideal depende de como os consumidores recebem as mensagens, da possibilidade de expor seus endpoints e da necessidade de entrega seletiva.
|
Modelo |
Funcionamento |
Visibilidade do consumidor |
Filtragem de mensagens |
Mais indicado para |
|
Baseado em fila |
Um cliente envia mensagens para uma fila. Vários consumidores recuperam as mensagens por pull, mas cada mensagem vai para apenas um consumidor. |
Endpoints permanecem privados |
Não suportado |
Distribuição de tarefas ponto a ponto |
|
Baseado em tópico |
Um cliente publica mensagens em um tópico. O SMQ envia mensagens via push para todos os consumidores inscritos. |
Endpoints devem ser expostos |
Suportado via filtros de assinatura |
Notificações push em tempo real |
|
Combinado (este tutorial) |
Um cliente publica em um tópico. O tópico envia mensagens via push para várias filas. Cada consumidor recupera as mensagens de sua própria fila por pull. |
Endpoints permanecem privados |
Suportado via filtros de assinatura |
Distribuição (fan-out) com consumidores privados |
O padrão combinado é adequado para cenários em que uma mensagem precisa alcançar vários consumidores cujos endpoints não podem ser expostos — por exemplo, consumidores executando dentro de uma rede privada.
Cenário de exemplo: Um sistema de processamento de pedidos publica cada novo pedido em um tópico. Filas separadas alimentam os serviços de atendimento, análise e notificação. Cada serviço recupera os pedidos de sua própria fila de forma independente, sem expor um endpoint de entrada.
Como funciona
O padrão combinado conecta um tópico a várias filas por meio de assinaturas. Uma assinatura atua como uma fila virtual: ela recebe uma cópia de cada mensagem publicada no tópico, e os consumidores recuperam as mensagens dela por pull exatamente como fariam de uma fila comum.
A configuração segue estas etapas:
Crie um tópico e uma fila por consumidor.
Inscreva cada fila no tópico. O endpoint da fila torna-se o destino da assinatura.
O produtor publica uma mensagem no tópico.
O SMQ copia a mensagem para todas as filas inscritas.
Cada consumidor recupera sua cópia de sua própria fila por pull.

Como os consumidores recuperam as mensagens das filas por pull em vez de recebê-las via push, seus endpoints nunca ficam expostos ao SMQ ou uns aos outros.
Pré-requisitos
Antes de começar, certifique-se de ter:
IntelliJ IDEA ou Eclipse instalado (este tutorial usa IntelliJ IDEA)
JDK 1.8 ou posterior
Apache Maven 2.5 ou posterior
Instale a dependência Java
Adicione a dependência do SDK do SMQ ao arquivo pom.xml do seu projeto Java:
<dependencies>
<dependency>
<groupId>com.aliyun.mns</groupId>
<artifactId>aliyun-sdk-mns</artifactId>
<version>1.1.9.2</version>
</dependency>
</dependencies>
Referência da API CloudPullTopic
O SDK para Java 1.1.8 introduziu a classe CloudPullTopic, que encapsula o padrão combinado de tópico e fila. Crie um objeto CloudPullTopic por meio do MNSClient:
// Full form: create queues automatically with a queue metadata template
public CloudPullTopic createPullTopic(
TopicMeta topicMeta,
Vector<String> queueNameList,
boolean needCreateQueue,
QueueMeta queueMetaTemplate
)
// Short form: use existing queues (no automatic creation)
public CloudPullTopic createPullTopic(
TopicMeta topicMeta,
Vector<String> queueNameList
)
|
Parâmetro |
Descrição |
|
|
Metadados do tópico (nome, propriedades). |
|
|
Lista de nomes de filas. Cada fila recebe uma cópia de toda mensagem publicada. |
|
|
Indica se as filas listadas em |
|
|
Modelo de metadados de fila aplicado a todas as filas criadas automaticamente (por exemplo, tempo de espera de polling). |
Publique e consuma mensagens
O exemplo abaixo usa CloudPullTopic para configurar a distribuição, publicar uma mensagem e recuperá-la por pull em três filas separadas.
package doc;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.client.CloudPullTopic;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.model.QueueMeta;
import com.aliyun.mns.model.TopicMeta;
import com.aliyun.mns.model.TopicMessage;
import com.aliyun.mns.model.RawTopicMessage;
import com.aliyun.mns.model.Message;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.common.ClientException;
import java.util.Vector;
public class DemoTopicMessageBroadcast {
public static void main(String[] args) {
// Initialize the client with your AccessKey ID, AccessKey Secret, and endpoint.
CloudAccount account = new CloudAccount(
ServiceSettings.getMNSAccessKeyId(),
ServiceSettings.getMNSAccessKeySecret(),
ServiceSettings.getMNSAccountEndpoint());
MNSClient client = account.getMNSClient();
// Define three consumer queues.
Vector<String> consumerNameList = new Vector<String>();
String consumerName1 = "consumer001";
String consumerName2 = "consumer002";
String consumerName3 = "consumer003";
consumerNameList.add(consumerName1);
consumerNameList.add(consumerName2);
consumerNameList.add(consumerName3);
// Set long polling to 30 seconds for the auto-created queues.
QueueMeta queueMetaTemplate = new QueueMeta();
queueMetaTemplate.setPollingWaitSeconds(30);
try {
// --- Producer: create a topic and publish a message ---
String topicName = "demo-topic-for-pull";
TopicMeta topicMeta = new TopicMeta();
topicMeta.setTopicName(topicName);
// createPullTopic creates the topic, creates the three consumer queues,
// and subscribes each queue to the topic — all in one call.
CloudPullTopic pullTopic = client.createPullTopic(
topicMeta, consumerNameList, true, queueMetaTemplate);
// Publish a raw message to the topic. SMQ copies it into all subscribed queues.
String messageBody = "broadcast message to all the consumers:hello the world.";
TopicMessage tMessage = new RawTopicMessage();
tMessage.setBaseMessageBody(messageBody);
pullTopic.publishMessage(tMessage);
// --- Consumers: pull the message from each queue ---
CloudQueue queueForConsumer1 = client.getQueueRef(consumerName1);
CloudQueue queueForConsumer2 = client.getQueueRef(consumerName2);
CloudQueue queueForConsumer3 = client.getQueueRef(consumerName3);
// popMessage(30) waits up to 30 seconds for a message (long polling).
Message consumer1Msg = queueForConsumer1.popMessage(30);
if (consumer1Msg != null) {
System.out.println("consumer1 received: "
+ consumer1Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer1 queue is empty");
}
Message consumer2Msg = queueForConsumer2.popMessage(30);
if (consumer2Msg != null) {
System.out.println("consumer2 received: "
+ consumer2Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer2 queue is empty");
}
Message consumer3Msg = queueForConsumer3.popMessage(30);
if (consumer3Msg != null) {
System.out.println("consumer3 received: "
+ consumer3Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer3 queue is empty");
}
// Clean up: delete the topic, its subscriptions, and all associated queues.
pullTopic.delete();
} catch (ClientException ce) {
System.out.println("Network error between the client and SMQ. "
+ "Check your network and DNS settings.");
ce.printStackTrace();
} catch (ServiceException se) {
se.printStackTrace();
}
client.close();
}
}
Verifique o resultado
Após executar o exemplo, confirme se cada consumidor recebeu a mensagem. Saída esperada:
consumer1 received: broadcast message to all the consumers:hello the world.
consumer2 received: broadcast message to all the consumers:hello the world.
consumer3 received: broadcast message to all the consumers:hello the world.
Se uma fila exibir "queue is empty", a mensagem pode ainda não ter sido entregue. Aumente o tempo limite de popMessage ou verifique se o tópico e as assinaturas foram criados corretamente.
Explicação do código
|
Etapa |
O que acontece |
|
Inicializar |
Autentica com seu AccessKey ID, AccessKey Secret e endpoint do SMQ. |
|
Chamar |
Cria o tópico, cria as três filas de consumidores e inscreve cada fila no tópico. |
|
Chamar |
Publica uma mensagem bruta ( |
|
Chamar |
Cada consumidor recupera sua cópia por pull com um tempo limite de long polling de 30 segundos. |
|
Chamar |
Exclui o tópico, suas assinaturas e todas as filas associadas. |
O exemplo publica uma mensagem bruta (RawTopicMessage). Analise mensagens brutas comgetMessageBodyAsRawString(). Se você usarBase64TopicMessage, analise comgetMessageBodyAsString().
Próximos passos
Explore outros padrões de mensagens do SMQ em Referência para SDKs da Nova Versão (Recomendado).