RocketMQ入門

kopoo發表於2021-04-18

RocketMQ簡介

image
image
image

RocketMQ基本概念

image
image
image

RocketMQ安裝執行

wusi@wusi-virtual-machine:~/桌面$ sudo wget https://archive.apache.org/dist/rocketmq/4.7.1/rocketmq-all-4.7.1-bin-release.zip
wusi@wusi-virtual-machine:~/桌面$ unzip rocketmq-all-4.7.1-bin-release.zip
root@wusi-virtual-machine:/home/wusi/桌面/rocketmq-all-4.7.1-bin-release# mkdir log
root@wusi-virtual-machine:/home/wusi/桌面/rocketmq-all-4.7.1-bin-release# nohup bin/mqnamesrv > log/mqname.log  2>&1  &
root@wusi-virtual-machine:/home/wusi/桌面/rocketmq-all-4.7.1-bin-release# nohup bin/mqbroker -n 172.16.20.246:9876 -c conf/broker.conf autoCreateTopicEnable=true >   log/borker.log 2>&1 &

2>&1 的意思就是將標準錯誤重定向到標準輸出。
還需要修改runserver.sh,不要設定的太大
image
修改conf目錄下的broker.conf
image
修改runbroker.sh,不要設定的太大
image

RocketMQ架構方案及角色詳解

image
image
image

API的使用

生產者啟動後,傳送訊息時會報以下錯:
Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: No route info of this topic, TopicTest

原因:
使用RocketMQ進行發訊息時,必須要指定topic,對於topic的設定有一個開關autoCreateTopicEnable,一般在開發測試環境中會使用預設設定autoCreateTopicEnable = true,
但是這樣就會導致topic的設定不容易規範管理,沒有統一的稽核等等,所以在正式環境中會在Broker啟動時設定引數autoCreateTopicEnable = false。

但是,目前的版本中,autoCreateTopicEnable設定為true也不會生效

解決方法:
手動通過命令或管理介面建立主題

/usr/rocketmq/bin/mqadmin updateTopic -n '192.168.100.242:9876' -c DefaultCluster -t TopicTest

消費者程式碼

package com.study.rocketmq.a151_simple;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;

import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * 普通訊息消費者
 */
public class Consumer {

    public static final String NAME_SERVER_ADDR = "192.168.100.242:9876";

    public static void main(String[] args) throws MQClientException {
        // 1. 建立消費者(Push)物件
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("GROUP_TEST");

        // 2. 設定NameServer的地址,如果設定了環境變數NAMESRV_ADDR,可以省略此步
        consumer.setNamesrvAddr(NAME_SERVER_ADDR);
        consumer.setMaxReconsumeTimes(-1);// 消費重試次數 -1代表16次
        // 3. 訂閱對應的主題和Tag
        consumer.subscribe("TopicTest", "*");

        // 4. 註冊訊息接收到Broker訊息後的處理介面
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                try {
                    MessageExt messageExt = list.get(0);
                    System.out.printf("執行緒:%-25s 接收到新訊息 %s --- %s %n", Thread.currentThread().getName(), messageExt.getTags(), new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
        });

        // 5. 啟動消費者(必須在註冊完訊息監聽器後啟動,否則會報錯)
        consumer.start();

        System.out.println("已啟動消費者");
    }
}

同步生產者程式碼

package com.study.rocketmq.a151_simple;

import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;

/**
 * 傳送同步訊息
 * 可靠的同步傳輸用於廣泛的場景,如重要的通知訊息,簡訊通知,簡訊營銷系統等。
 */
public class SyncProducer {
    public static final String NAME_SERVER_ADDR = "192.168.100.242:9876";
    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException, MQBrokerException {
        // 1. 建立生產者物件
        DefaultMQProducer producer = new DefaultMQProducer("GROUP_TEST");

        // 2. 設定NameServer的地址,如果設定了環境變數NAMESRV_ADDR,可以省略此步
        producer.setNamesrvAddr(NAME_SERVER_ADDR);

        // 3. 啟動生產者
        producer.start();

        // 4. 生產者傳送訊息
        for (int i = 0; i < 10; i++) {
            Message message = new Message("TopicTest", "TagA", ("Hello MQ:" + i).getBytes(RemotingHelper.DEFAULT_CHARSET));

            SendResult result = producer.send(message);

            System.out.printf("傳送結果:%s%n", result);
        }

        // 5. 停止生產者
        producer.shutdown();
    }
}

image
image
非同步生產者

package com.study.rocketmq.a151_simple;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;
import java.util.concurrent.CountDownLatch;

/**
 * 非同步訊息
 * 一般用來對方法呼叫響應時間有較嚴格要求的情況下,非同步呼叫,立即返回
 * 不同於同步的唯一在於: send方法呼叫的時候多攜帶一個回撥介面引數,用來非同步處理訊息傳送結果
 */
public class AsyncProducer {
    public static final String NAME_SERVER_ADDR = "192.168.100.242:9876";
    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException {
        // 1:建立生產者物件,並指定組名
        DefaultMQProducer producer = new DefaultMQProducer("GROUP_TEST");

        // 2:指定NameServer地址
        producer.setNamesrvAddr(NAME_SERVER_ADDR);

        // 3:啟動生產者
        producer.start();
        producer.setRetryTimesWhenSendAsyncFailed(0); // 設定非同步傳送失敗重試次數,預設為2

        int count = 10;
        CountDownLatch cd = new CountDownLatch(count);
        // 4:迴圈傳送訊息
        for (int i = 0; i < count; i++) {
            final int index = i;

            // ID110:業務資料的ID,比如使用者ID、訂單編號等等
            Message msg = new Message("TopicTest", "TagB", "ID110", ("Hello World " + index).getBytes(RemotingHelper.DEFAULT_CHARSET));
            // 傳送非同步訊息
            producer.send(msg, new SendCallback() {
                /**
                 * 傳送成功的回撥函式
                 * 但會結果有多種狀態,在SendStatus列舉中定義
                 * @param sendResult
                 */
                public void onSuccess(SendResult sendResult) {
                    System.out.printf("%-10d OK MSG_ID:%s %n", index, sendResult.getMsgId());
                    cd.countDown();
                }

                /**
                 * 傳送失敗的回撥函式
                 * @param e
                 */
                public void onException(Throwable e) {
                    System.out.printf("%-10d Exception %s %n", index, e);
                    e.printStackTrace();
                    cd.countDown();
                }
            });
        }

        // 確保訊息都傳送出去了
        cd.await();
        // 5:關閉生產者
        producer.shutdown();
    }
}

image
image
單向模式

package com.study.rocketmq.a151_simple;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;

/**
 * 單向模式
 * 一般用來對可靠性有一定要求的訊息傳送,例如日誌系統
 * 不同於同步的唯一之處在於:呼叫的是sendOneway方法,且方法不返回任何值,即呼叫者不需要關心成功或失敗
 */
public class OnewayProducer {
    public static final String NAME_SERVER_ADDR = "192.168.100.242:9876";

    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException {
        // 1:建立生產者物件
        DefaultMQProducer producer = new DefaultMQProducer("GROUP_TEST");

        // 2:指定NameServer地址
        producer.setNamesrvAddr(NAME_SERVER_ADDR);

        // 3:啟動生產者
        producer.start();

        // 4:傳送訊息
        for (int i = 0; i < 10; i++) {
            Message msg = new Message("TopicTest", "TagC", ("Hello OneWay :" + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
            producer.sendOneway(msg);
        }
        System.out.println("訊息已傳送");

        producer.shutdown();
    }
}

image
image

都是連線NAME_SERVER然後選擇相應的叢集

image

訊息的高可用

從記憶體將訊息寫入磁碟,然後將訊息同步到從伺服器中,資料有同步寫入和非同步寫入倆種方式,master之間沒有通訊

可以理解為同步就是訊息立刻寫入
非同步就是訊息累計一段時間後寫入

image
雙寫、同步複製
image
雙主雙從,四臺機器屬於同一個叢集
image

相關文章