傳送不同型別的訊息
傳送不同型別的訊息
普通訊息
RocketMQ提供三種方式來傳送普通訊息:可靠同步傳送、可靠非同步傳送和單向傳送。
可靠同步傳送
同步傳送是指訊息傳送方發出資料後,會在收到接收方發回響應之後才發下一個資料包的通訊方式。
此種方式應用場景非常廣泛,例如重要通知郵件、報名簡訊通知、營銷簡訊系統等
可靠非同步傳送
非同步傳送是指傳送方發出資料後,不等接收方發回響應,接著傳送下個資料包的通訊方式。傳送方通過
回撥介面接收伺服器響應,並對響應結果進行處理。
非同步傳送一般用於鏈路耗時較長,對 RT 響應時間較為敏感的業務場景,例如使用者視訊上傳後通知
啟動轉碼服務,轉碼完成後通知推送轉碼結果等。
單向傳送
單向傳送是指傳送方只負責傳送訊息,不等待伺服器回應且沒有回撥函式觸發,即只傳送請求不
等待應答。
適用於某些耗時非常短,但對可靠性要求並不高的場景,例如日誌收集。
測試程式碼:
匯入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
package com.wxit.test;
import com.wxit.OrderApplication;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @Author wj
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderApplication.class)
public class MessageTypeTest {
@Autowired
private RocketMQTemplate rocketMQTemplate;
//同步訊息
@Test
public void testSyncSend(){
//引數一:topic:tag
//引數二:訊息體
//引數三:超時時間
SendResult result = rocketMQTemplate.syncSend("test-topic-1:tag", "這是一條同步訊息", 10000);
System.out.println(result);
}
//非同步訊息
@Test
public void testAsyncSend() throws InterruptedException {
rocketMQTemplate.asyncSend("test-topic-1", "這是一條非同步訊息", new SendCallback() {
//成功響應的回撥
@Override
public void onSuccess(SendResult result) {
System.out.println(result);
}
//異常響應的回撥
@Override
public void onException(Throwable throwable) {
System.out.println(throwable);
}
});
System.out.println("=============");
Thread.sleep(3000000);
}
@Test
//單向訊息
public void testOneWay(){
for (int i = 0; i < 10; i++) {
rocketMQTemplate.sendOneWay("test-topic-1","這是一條單向訊息");
}
}
}
順序訊息
順序訊息是訊息佇列提供的一種嚴格按照順序來發布和消費的訊息型別。
@Test
public void testOneWayOrderly(){
//
for (int i = 0; i < 10; i++) {
rocketMQTemplate.sendOneWayOrderly("test-topic-1","這是一條單向訊息","xx");
}
}
事務訊息
RocketMQ提供了事務訊息,通過事務訊息就能達到分散式事務的最終一致
事務訊息互動流程
兩個概念
半事務訊息:暫不能投遞的訊息,傳送方已經成功地將訊息傳送到了RocketMQ服務端,但是服務
端未收到生產者對該訊息的二次確認,此時該訊息被標記成“暫不能投遞”狀態,處於該種狀態下的
訊息即半事務訊息。
訊息回查:由於網路閃斷、生產者應用重啟等原因,導致某條事務訊息的二次確認丟失,
RocketMQ服務端通過掃描發現某條訊息長期處於“半事務訊息”時,需要主動向訊息生產者詢問該
訊息的最終狀態(Commit 或是 Rollback),該詢問過程即訊息回查。
事務訊息傳送步驟
\1. 傳送方將半事務訊息傳送至RocketMQ服務端。
\2. RocketMQ服務端將訊息持久化之後,向傳送方返回Ack確認訊息已經傳送成功,此時訊息為半事
務訊息。
\3. 傳送方開始執行本地事務邏輯。
\4. 傳送方根據本地事務執行結果向服務端提交二次確認(Commit 或是 Rollback),服務端收到
Commit 狀態則將半事務訊息標記為可投遞,訂閱方最終將收到該訊息;服務端收到 Rollback 狀
態則刪除半事務訊息,訂閱方將不會接受該訊息。
事務訊息回查步驟
\1. 在斷網或者是應用重啟的特殊情況下,上述步驟4提交的二次確認最終未到達服務端,經過固定時
間後服務端將對該訊息發起訊息回查。
\2. 傳送方收到訊息回查後,需要檢查對應訊息的本地事務執行的最終結果。
\3. 傳送方根據檢查得到的本地事務的最終狀態再次提交二次確認,服務端仍按照步驟4對半事務訊息
進行操作
程式碼示例
package com.wxit.domain;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
//訊息事物狀態記錄
@Entity(name = "shop_txlog")
@Data
public class TxLog {
@Id
private String txId;
private Date date;
}
package com.wxit.service.impl;
import com.wxit.dao.OrderDao;
import com.wxit.dao.TxLogDao;
import com.wxit.domain.Order;
import com.wxit.domain.TxLog;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.UUID;
/**
* @Author wj
**/
@Service
public class OrderServiceImpl4 {
@Autowired
private OrderDao orderDao;
@Autowired
private TxLogDao txLogDao;
@Autowired
private RocketMQTemplate rocketMQTemplate;
//傳送半事務訊息
public void createOrderBefore(Order order){
String txId = UUID.randomUUID().toString();
rocketMQTemplate.sendMessageInTransaction(
"tx_producer_group",
"tx_topic",
MessageBuilder.withPayload(order).setHeader("txId",txId).build(),
order
);
}
@Transactional
public void createOrder(String txId,Order order){
orderDao.save(order);
TxLog txLog = new TxLog();
txLog.setTxId(txId);
txLog.setDate(new Date());
txLogDao.save(txLog);
}
}
package com.wxit.service.impl;
import com.wxit.dao.TxLogDao;
import com.wxit.domain.Order;
import com.wxit.domain.TxLog;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
/**
* @Author wj
**/
@Service
@RocketMQTransactionListener(txProducerGroup = "tx_producer_group")
public class OrderServiceImpl4Listener implements RocketMQLocalTransactionListener {
@Autowired
private OrderServiceImpl4 orderServiceImpl4;
@Autowired
private TxLogDao txLogDao;
//執行本地事務
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
String txId = (String) msg.getHeaders().get("txId");
try {
//本地事務
Order order = (Order) arg;
orderServiceImpl4.createOrder(txId,order);
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e){
return RocketMQLocalTransactionState.ROLLBACK;
}
}
//訊息回查
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String txId = (String) msg.getHeaders().get("txId");
TxLog txLog = txLogDao.findById(txId).get();
if (txLog != null){
//本地事務訂單成功
return RocketMQLocalTransactionState.COMMIT;
} else {
return RocketMQLocalTransactionState.ROLLBACK;
}
}
}
訊息消費要注意的細節
@Slf4j
@Service
@RocketMQMessageListener(
consumerGroup = "shop-user",//消費者分組
topic = "order-topic",//要消費的主題
consumeMode = ConsumeMode.CONCURRENTLY, //消費模式:無序和有序
messageModel = MessageModel.CLUSTERING//訊息模式:廣播和叢集,預設是叢集
)
public class SmsService implements RocketMQListener<Order> {
@Override
public void onMessage(Order message) {
log.info("接收到了一個訂單資訊{},接下來就可以傳送簡訊通知了", message);
}
}
RocketMQ支援兩種訊息模式:
廣播消費: 每個消費者例項都會收到訊息,也就是一條訊息可以被每個消費者例項處理;
叢集消費: 一條訊息只能被一個消費者例項消費
相關文章
- python requests傳送不同型別的資料Python型別
- 訊息中介軟體—RocketMQ訊息傳送MQ
- 【RocketMQ】MQ訊息傳送MQ
- RocketMQ(八):訊息傳送MQ
- iOS 傳送位置訊息iOS
- 鴻蒙傳送訊息通知鴻蒙
- php ActiveMQ的傳送訊息,與處理訊息PHPMQ
- 多種訊息傳送機制,處理合適不??
- RocketMQ中Producer訊息的傳送MQ
- RocketMQ(九):訊息傳送(續)MQ
- TNW-傳送模板訊息TNW
- 6-RocketMQ傳送訊息MQ
- 傳送kafka訊息的shell指令碼Kafka指令碼
- 如何在linux中傳送訊息給別的控制檯Linux
- RocketMQ -- 訊息傳送儲存流程MQ
- Kafka -- 訊息傳送儲存流程Kafka
- 快速向 Google Chat 傳送訊息Go
- iOS 給父類傳送訊息iOS
- 小程式傳送訂閱訊息
- Kafka、RabbitMQ、RocketMQ訊息中介軟體的對比 —— 訊息傳送效能KafkaMQ
- 用程式碼理解 ObjC 中的傳送訊息和訊息轉發OBJ
- 用程式碼理解ObjC中的傳送訊息和訊息轉發OBJ
- Runtime備忘-訊息傳送流程
- 分散式事務:訊息可靠傳送分散式
- django+小程式傳送模板訊息Django
- Python呼叫飛書傳送訊息Python
- WIN32傳送自定義訊息Win32
- 以事務方式傳送 Kafka 訊息Kafka
- 一張圖進階 RocketMQ - 訊息傳送MQ
- RocketMQ - 生產者訊息傳送流程MQ
- [Akka]傳送一條訊息的內部流程
- 從原始碼看 ObjC 中訊息的傳送原始碼OBJ
- Laravel 佇列訊息與傳送郵件Laravel佇列
- Android Handler 訊息傳送效能優化Android優化
- RocketMQ(6)---傳送普通訊息(三種方式)MQ
- Pulsar訊息傳送、消費架構概述架構
- iOS 訊息傳送與轉發詳解iOS
- OCX 控制元件主動傳送訊息給 MFC 視窗訊息控制元件