Rocket MQ傳送訊息的三種方式初析

FeelTouch發表於2018-08-13

前言

MQ 傳送訊息有三種實現方式:可靠同步傳送、可靠非同步傳送、單向(Oneway)傳送。基於版本4.2.0+。注意:順序訊息只支援可靠同步傳送。

可靠同步傳送

原理:同步傳送是指訊息傳送方發出資料後,會在收到接收方發回響應之後才發下一個資料包的通訊方式。

場景:此種方式應用場景非常廣泛,例如重要通知郵件、報名簡訊通知、營銷簡訊系統等。

sync-send

可靠非同步傳送

原理:非同步傳送是指傳送方發出資料後,不等接收方發回響應,接著傳送下個資料包的通訊方式。 MQ 的非同步傳送,需要使用者實現非同步傳送回撥介面(SendCallback)。訊息傳送方在傳送了一條訊息後,不需要等待伺服器響應即可返回,進行第二條訊息傳送。傳送方通過回撥介面接收伺服器響應,並對響應結果進行處理。

場景:非同步傳送一般用於鏈路耗時較長,對 RT 響應時間較為敏感的業務場景,例如使用者視訊上傳後通知啟動轉碼服務,轉碼完成後通知推送轉碼結果等。

async_send

單向(Oneway)傳送

原理:單向(Oneway)傳送特點為傳送方只負責傳送訊息,不等待伺服器回應且沒有回撥函式觸發,即只傳送請求不等待應答。 此方式傳送訊息的過程耗時非常短,一般在微秒級別。

場景:適用於某些耗時非常短,但對可靠性要求並不高的場景,例如日誌收集。

oneway

三者的特點和主要區別。

傳送方式 傳送 TPS 傳送結果反饋 可靠性
同步傳送 不丟失
非同步傳送 不丟失
單向傳送 最快 可能丟失

code 實戰

同步傳送

public class ProducerTest {
    public static void main(String[] args) {
        Properties properties = new Properties();
        Producer producer = ONSFactory.createProducer(properties);
        // 在傳送訊息前,必須呼叫 start 方法來啟動 Producer,只需呼叫一次即可
        producer.start();
        //迴圈傳送訊息
        for (int i = 0; i < 100; i++){
            Message msg = new Message( //
                // Message 所屬的 Topic
                "TopicTestMQ",
                // Message Tag 可理解為 Gmail 中的標籤,對訊息進行再歸類,方便 Consumer 指定過濾條件在 MQ 伺服器過濾
                "TagA",
                // Message Body 可以是任何二進位制形式的資料, MQ 不做任何干預,
                // 需要 Producer 與 Consumer 協商好一致的序列化和反序列化方式
                "Hello MQ".getBytes());
            // 設定代表訊息的業務關鍵屬性,請儘可能全域性唯一。
            // 以方便您在無法正常收到訊息情況下,可通過阿里雲伺服器管理控制檯查詢訊息並補發
            // 注意:不設定也不會影響訊息正常收發
            msg.setKey("ORDERID_" + i);
            try {
                SendResult sendResult = producer.send(msg);
                // 同步傳送訊息,只要不拋異常就是成功
                if (sendResult != null) {
                    System.out.println(new Date() + " Send mq message success. Topic is:" + msg.getTopic() + " msgId is: " + sendResult.getMessageId());
                }
            }
            catch (Exception e) {
                // 訊息傳送失敗,需要進行重試處理,可重新傳送這條訊息或持久化這條資料進行補償處理
                System.out.println(new Date() + " Send mq message failed. Topic is:" + msg.getTopic());
                e.printStackTrace();
            }
        }
        // 在應用退出前,銷燬 Producer 物件
        // 注意:如果不銷燬也沒有問題
        producer.shutdown();
    }
}

非同步傳送

    public static void main(String[] args) {
        Properties properties = new Properties();
        Producer producer = ONSFactory.createProducer(properties);
        // 在傳送訊息前,必須呼叫 start 方法來啟動 Producer,只需呼叫一次即可。
        producer.start();
        Message msg = new Message(
                // Message 所屬的 Topic
                "TopicTestMQ",
                // Message Tag,可理解為 Gmail 中的標籤,對訊息進行再歸類,方便 Consumer 指定過濾條件在 MQ 伺服器過濾
                "TagA",
                // Message Body,任何二進位制形式的資料,MQ 不做任何干預,需要 Producer 與 Consumer 協商好一致的序列化和反序列化方式
                "Hello MQ".getBytes());
        // 設定代表訊息的業務關鍵屬性,請儘可能全域性唯一。 以方便您在無法正常收到訊息情況下,可通過 MQ 控制檯查詢訊息並補發。
        // 注意:不設定也不會影響訊息正常收發
        msg.setKey("ORDERID_100");
        // 非同步傳送訊息, 傳送結果通過 callback 返回給客戶端。
        producer.sendAsync(msg, new SendCallback() {
            @Override
            public void onSuccess(final SendResult sendResult) {
                // 消費傳送成功
                System.out.println("send message success. topic=" + sendResult.getTopic() + ", msgId=" + sendResult.getMessageId());
            }
            @Override
            public void onException(OnExceptionContext context) {
                // 訊息傳送失敗,需要進行重試處理,可重新傳送這條訊息或持久化這條資料進行補償處理
                System.out.println("send message failed. topic=" + context.getTopic() + ", msgId=" + context.getMessageId());
            }
        });
        // 在 callback 返回之前即可取得 msgId。
        System.out.println("send message async. topic=" + msg.getTopic() + ", msgId=" + msg.getMsgID());
        // 在應用退出前,銷燬 Producer 物件。 注意:如果不銷燬也沒有問題
        producer.shutdown();
    }

單向(Oneway)傳送

 public static void main(String[] args) {
        Properties properties = new Properties();
        Producer producer = ONSFactory.createProducer(properties);
        // 在傳送訊息前,必須呼叫 start 方法來啟動 Producer,只需呼叫一次即可。
        producer.start();
        //迴圈傳送訊息
        for (int i = 0; i < 100; i++){
            Message msg = new Message(
                    // Message 所屬的 Topic
                    "TopicTestMQ",
                    // Message Tag,
                    // 可理解為 Gmail 中的標籤,對訊息進行再歸類,方便 Consumer 指定過濾條件在 MQ 伺服器過濾
                    "TagA",
                    // Message Body
                    // 任何二進位制形式的資料,MQ 不做任何干預,需要 Producer 與 Consumer 協商好一致的序列化和反序列化方式
                    "Hello MQ".getBytes());
            // 設定代表訊息的業務關鍵屬性,請儘可能全域性唯一。
            // 以方便您在無法正常收到訊息情況下,可通過阿里雲伺服器管理控制檯查詢訊息並補發。
            // 注意:不設定也不會影響訊息正常收發
            msg.setKey("ORDERID_" + i);
            // 由於在 oneway 方式傳送訊息時沒有請求應答處理,一旦出現訊息傳送失敗,則會因為沒有重試而導致資料丟失。若資料不可丟,建議選用可靠同步或可靠非同步傳送方式。
            producer.sendOneway(msg);
        }
        // 在應用退出前,銷燬 Producer 物件
        // 注意:如果不銷燬也沒有問題
        producer.shutdown();
    }

 

相關文章