本篇文章將使用RocketMQ以三種方式發送消息:可靠的同步,可靠的異步和單向傳輸。並介紹下負載均衡模式與廣播模式的區別:
(1)同步發送消息:
在重要的通知消息,SMS通知,SMS營銷系統等廣泛的場景中使用可靠的同步傳輸。
生產者代碼:
/**
* 發送同步消息
* 這種可靠性同步地發送方式使用的比較廣泛,比如:重要的消息通知,短信通知。
*/
public class SyncProducer {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
//1.創建消息生產者producer,並指定生產者組名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("group1");
//2.指定NameServer地址
defaultMQProducer.setNamesrvAddr("192.168.160.131:9876");
//3.啓動producer
defaultMQProducer.start();
//4.創建消息對象,指定主題topic、tag和消息體
for (int i = 0; i < 5; i++) {
/*
* 參數一:消息主題Topic
* 參數二:消息tag
* 參數三:消息內容
*/
Message message = new Message("base", "tag1", ("hello world" + i).getBytes());
//5.發送消息
SendResult result = defaultMQProducer.send(message);
System.out.println("result:"+result);
//睡眠1秒
TimeUnit.SECONDS.sleep(1);
}
//6.關閉生產者producer
defaultMQProducer.shutdown();
}
}
(2)異步發送消息
異步傳輸通常用於對時間敏感的業務場景中。
生產者代碼:
/**
* 發送異步消息
* 異步消息通常用在對響應時間敏感的業務場景,即發送端不能容忍長時間地等待Broker的響應。
*/
@Slf4j
public class AsyncProducer {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException {
//1.創建消息生產者producer,並指定生產者組名
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("group1");
//2.指定NameServer地址
defaultMQProducer.setNamesrvAddr("192.168.160.131:9876");
//3.啓動producer
defaultMQProducer.start();
for (int i = 0; i < 10; i++) {
//4.創建消息對象,指定主題topic、tag和消息體
/*
* 參數一:消息主題Topic
* 參數二:消息tag
* 參數三:消息內容
*/
Message message = new Message("base", "tag2", ("hello world" + i).getBytes());
//5.發送異步消息
defaultMQProducer.send(message, new SendCallback() {
//發送成功回調
@Override
public void onSuccess(SendResult sendResult) {
log.debug("sendResult:{}", sendResult);
}
//發送失敗回調
@Override
public void onException(Throwable throwable) {
log.error("throwable:",throwable);
}
});
TimeUnit.SECONDS.sleep(1);
}
//6.關閉生產者producer
defaultMQProducer.shutdown();
}
}
(3)以單向模式發送消息
單向傳輸用於要求中等可靠性的情況,例如日誌收集。
生產者代碼:
/**
* 單向發送
* 這種方式主要用在不特別關心發送結果的場景,例如日誌發送
* @author 13871
*/
@Slf4j
public class OneWayProducer {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException {
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("group1");
defaultMQProducer.setNamesrvAddr("192.168.160.131:9876");
defaultMQProducer.start();
for (int i = 0; i < 10; i++) {
Message message = new Message("base", "tag3", ("單向消息" + i).getBytes());
defaultMQProducer.sendOneway(message);
// TimeUnit.SECONDS.sleep(1);
}
defaultMQProducer.shutdown();
}
}
消費者代碼:(用於以上三種生產者消費)
/**
* 消費者
*/
@Slf4j
public class consumer {
public static void main(String[] args) throws MQClientException {
//1.創建消費者Consumer,指定組名
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("group1");
//2.指定NameServer地址
defaultMQPushConsumer.setNamesrvAddr("192.168.160.131:9876");
//3.訂閱主題topic和tag
defaultMQPushConsumer.subscribe("base", "*");
//消費者默認是負載均衡,設置成廣播模式
//defaultMQPushConsumer.setMessageModel(MessageModel.BROADCASTING);
//4.設置回調函數,處理消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
//指定消息內容
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg:list) {
System.out.println("msg:"+new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//5.啓動consumer
defaultMQPushConsumer.start();
}
}
ps:消費者默認是負載均衡,可以設置成廣播模式;
如果消費者是負載均衡的話:
consumer1:消費者端
msg:hello world0
msg:hello world3
msg:hello world4
consumer2:消費者端
msg:hello world1
msg:hello world2
也就是採用默認負載均衡模式的話,一個生產者端發送5條消息,兩個消費者端去消費,是兩者分攤,輪着來的,這時候一個消費3條,一個消費2條;
廣播模式:
由於廣播模式下要求一條消息需要投遞到一個消費組下面所有的消費者實例,所以也就 沒有消息被分攤消費的說法。 在實現上,其中一個不同就是在consumer分配queue的時候,所有consumer都分到所 有的queue。
以同步發送消息的生產者代碼爲例,啓動生產者端,然後啓動兩個消費者端,查看控制檯:
生產者端,控制檯:(發送5條消息)
result:SendResult [sendStatus=SEND_OK, msgId=24098A1E7A3ECE402C3D4AADC1A10079000018B4AAC2469D7E3D0000, offsetMsgId=C0A8A08300002A9F0000000000019EE5, messageQueue=MessageQueue [topic=base, brokerName=localhost.localdomain, queueId=0], queueOffset=19]
result:SendResult [sendStatus=SEND_OK, msgId=24098A1E7A3ECE402C3D4AADC1A10079000018B4AAC2469D82350001, offsetMsgId=C0A8A08300002A9F0000000000019FBD, messageQueue=MessageQueue [topic=base, brokerName=localhost.localdomain, queueId=1], queueOffset=20]
result:SendResult [sendStatus=SEND_OK, msgId=24098A1E7A3ECE402C3D4AADC1A10079000018B4AAC2469D862D0002, offsetMsgId=C0A8A08300002A9F000000000001A095, messageQueue=MessageQueue [topic=base, brokerName=localhost.localdomain, queueId=2], queueOffset=31]
result:SendResult [sendStatus=SEND_OK, msgId=24098A1E7A3ECE402C3D4AADC1A10079000018B4AAC2469D8A190003, offsetMsgId=C0A8A08300002A9F000000000001A16D, messageQueue=MessageQueue [topic=base, brokerName=localhost.localdomain, queueId=3], queueOffset=30]
result:SendResult [sendStatus=SEND_OK, msgId=24098A1E7A3ECE402C3D4AADC1A10079000018B4AAC2469D8E040004, offsetMsgId=C0A8A08300002A9F000000000001A245, messageQueue=MessageQueue [topic=base, brokerName=localhost.localdomain, queueId=0], queueOffset=20]
17:05:31.676 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[192.168.160.131:10911] result: true
17:05:31.684 [NettyClientSelector_1] INFO RocketmqRemoting - closeChannel: close the connection to remote address[192.168.160.131:9876] result: true
消費者端,控制檯:(兩個消費者端,會消費同樣的消息,均是5條)
msg:hello world0
msg:hello world1
msg:hello world2
msg:hello world3
msg:hello world4