快速入門一篇搞定RocketMq-實現微服務實戰落地

sowler發表於2024-05-05

1、RocketMq介紹

RocketMQ起源於阿里巴巴,最初是為了解決郵件系統的高可靠性和高效能而設計的。在2016年開源分散式訊息中介軟體,並逐漸成為Apache頂級專案。現在是Apache的一個頂級專案,在阿里內部使用非常廣泛,已經經過了"雙11"這種萬億級的訊息流轉,效能穩定、高效。

官網地址:https://rocketmq.apache.org

快速開始文件:https://rocketmq.apache.org/docs/

Github地址:https://github.com/apache/rocketmq

2、RocketMq架構說明

RocketMQ的架構主要由Producer(訊息生產者)、Consumer(訊息消費者)、Broker(訊息中轉角色)和Name Server(網路路由角色)四個核心元件組成。Name Server負責維護Broker叢集和Topic資訊的路由中心,而Broker負責儲存和傳輸訊息。RocketMQ採用類似於Kafka的釋出訂閱模型,支援訊息的順序傳輸和事務性傳輸,同時可以配置不同的訊息過濾規則和重試策略。

3、下載

檢視微服務對應版本資訊,下載相關版本。檢視連線:https://github.com/alibaba/spring-cloud-alibaba/wiki/版本說明#2021x-分支

根據自己使用的Spring Cloud Alibaba Version選擇對應的版本進行下載即可。這裡下載4.4.0版本,下載地址:https://rocketmq.apache.org/download 下載成功後,為一個壓縮包檔案。把檔案上傳linux

使用命令解壓zip檔案並重新命名資料夾命令:

unzip rocketmq-all-4.4.0-bin-release.zip -d rocketmq-4.4.0

解壓成功後,如圖:

4、啟動

進入rocketmq-4.4.0目錄,檢視目錄結構。

  • benchmark:效能測試相關的資源,如果想要了解RocketMQ的基準測試,可以考慮使用該壓測工具。這個工具可以模擬生產者和消費者來測試RocketMQ叢集的效能。
  • bin:裡面是一些可執行檔案,管理rocketmq服務
  • conf:裡面就是一些配置檔案,包括broker配置檔案和logback配置檔案
  • lib:所依賴的第三方jar包
4.1、啟動Name Server命令
nohup sh bin/mqnamesrv -n 192.168.42.130:9876 > /dev/null 2>&1 &   # -n 後面IP為公網IP 必須指定其公網IP,不然會連線失敗

啟動成功後,預設啟動日誌在root目錄下。可以檢視啟動日誌資訊:

tail -f ~/logs/rocketmqlogs/namesrv.log

輸出下面資訊啟動成功:

也可以透過埠9876檢視是否啟動成功

ps -ef|grep 9876

4.2 啟動Broker命令
nohup sh bin/mqbroker -n 192.168.42.130:9876 -c conf/broker.conf autoCreateTopicEnable=true >/dev/null 2>&1 & # -n 後面IP為公網IP 必須指定其公網IP,不然會連線失敗

啟動日誌和啟動Name Server日誌在一個資料夾裡面。檢視啟動日誌資訊:

tail -n 50 ~/logs/rocketmqlogs/broker.log

可以透過jps 檢視啟動資訊如果能看到 NamesrvStartup 和 BrokerStartup 的話就表明單機版的 RocketMQ 啟動成功了

4.3 Rocketmq服務關閉

關閉 MQ使用 bin 目錄下的mqshutdown關閉服務

sh bin/mqshutdown namesrv #關閉namesrv服務

sh bin/mqshutdown broker #關閉broker服務 
4.4 啟動指令碼命令引數修改

在啟動的過程中,如果伺服器記憶體不足或者滿足不了啟動指令碼里面的預設記憶體配置,啟動的時候會啟動報錯。這是因為 apache-rocketmq/bin 目錄下啟動 nameserv 與 broker 的 runbroker.sh 和 runserver.sh 檔案中預設分配的記憶體太大,而系統實際記憶體卻太小導致啟動失敗。解決辦法就是修改runbroker.sh 和 runserver.sh裡的記憶體配置,調小一些即可。

首先先備份一份runbroker.sh 和 runserver.sh檔案,以防萬一改錯了。

cp runserver.sh runserver.sh.init

cp runbroker.sh runbroker.sh.init

修改:runserver.sh指令碼檔案,找到配置JVM引數的內容,把JVM配置引數調小:

JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn64m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=160m"

修改:runbroker.sh指令碼檔案

JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn64m"

5、測試訊息

透過上面的步驟,RocketMQ就啟動成功了。接下來我們可以在伺服器上面透過提供的測試指令碼進行訊息測試,驗證RocketMq是否可以正常使用。

生產者傳送訊息:

export NAMESRV_ADDR=127.0.0.1:9876

sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

透過輸出內容,我們可以檢視到訊息傳送成功了。下面執行監聽指令碼。測試消費者接受訊息:

sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

成功拿到訊息,可以說明RocketMq服務啟動成功了。

6、監控程式rocketmq-console

6.1、配置rocketmq-console

rocketmq-externals是RocketMq的擴充套件外掛專案。GitHub地址: https://github.com/apache/rocketmq-externals 之前rocketmq-console也在rocketmq-externals專案中。如今在GitHub apache/rocketmq-externals 專案下已經找不到 rocketmq-console模組了,官方已經從 apache/rocketmq-externals 獨立出來並更名為 rocketmq-dashboard。 我們可以檢視RocketMq官網配置儀表板說明 :RocketMQ 儀表板 |MQ (apache.org)

https://rocketmq.apache.org/docs/deploymentOperations/04Dashboard/

根據提示可以下載到原始碼內容

Github下載地址:https://github.com/apache/rocketmq-dashboard

如果是 5.0 版本的直接拉取最新的程式碼

 git clone https://github.com/apache/rocketmq-dashboard.git  

releases標籤中的rocketmq-dashboard-1.0.0版本試用於5.0版本以下的。

https://github.com/apache/rocketmq-dashboard/releases/tag/rocketmq-dashboard-1.0.0

下載成功後,使用IDEA開啟修改配置,改一下namesrvAddr配置項即可,如果沒有指定預設就是localhost:9876,如果namesrvAddr是叢集環境,每個節點使用;隔開。本地測試執行,執行成功後打包釋出的linux系統。

mvn clean package -Dmaven.test.skip=true #跳過測試
6.2 啟動rocketmq-console

指定NameServer的地址和啟動埠(8830)以及輸出日誌。由於內部不夠,設定JVM引數啟動,如果使用的linux系統記憶體足夠可以忽略jvm引數。啟動命令如下:

nohup java -jar -Xmx256M -Xms256M -XX:MaxMetaspaceSize=128M -XX:MetaspaceSize=128M rocketmq-dashboard-1.0.0.jar --server.port=8830 --rocketmq.config.namesrvAddr=127.0.0.1:9876 > /dev/null 2>&1 &

不指定JVM引數:

nohup java -jar  rocketmq-dashboard-1.0.0.jar --server.port=8830 --rocketmq.config.namesrvAddr=127.0.0.1:9876 > /dev/null 2>&1 &

執行成功後,檢視啟動日誌:

 tail -f ~/logs/consolelogs/rocketmq-console.log 

啟動成功。開放8830埠進行公網訪問。

監控成功。可以在叢集導航中檢視當前節點部署節點。

也可以看到上面測試的資料輸出:

7、微服務連線RockerMq

安全組需要開放10909、10911埠和9876埠,其中10909是VIP通道,10911是非VIP通道,9876是對外連線提供埠。不然連線傳送會報錯傳送超時 sendDefaultImpl call timeout; nested exception is org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout

maven引入依賴

        <!--RocketMQ-->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>

配置中心加入RocketMq配置

rocketmq: # rocketMQ配置
  # name server地址
  name-server: 192.168.42.130:9876
  consumer:
    pull-batch-size: 10
    group: blog_message
  producer:
    group: blog_message
    # 傳送訊息超時時間,預設3000
    sendMessageTimeout: 10000
    # 傳送訊息失敗重試次數,預設2
    retryTimesWhenSendFailed: 2
    # 非同步訊息重試此處,預設2
    retryTimesWhenSendAsyncFailed: 2
    # 訊息最大長度,預設1024 * 1024 * 4(預設4M)
    maxMessageSize: 4096
    # 壓縮訊息閾值,預設4k(1024 * 4)
    compressMessageBodyThreshold: 4096
    # 是否在內部傳送失敗時重試另一個broker,預設false
    retryNextServer: false

編寫RocketEnhanceConfig檔案,解決不支援Java時間型別配置

@Configuration
public class RocketEnhanceConfig {

    /**
     * 解決RocketMQ Jackson不支援Java時間型別配置
     * 原始碼參考:{@link org.apache.rocketmq.spring.autoconfigure}
     */
    @Bean
    @Primary
    public RocketMQMessageConverter enhanceRocketMQMessageConverter(){
        RocketMQMessageConverter converter = new RocketMQMessageConverter();
        CompositeMessageConverter compositeMessageConverter = (CompositeMessageConverter) converter.getMessageConverter();
        List<MessageConverter> messageConverterList = compositeMessageConverter.getConverters();
        for (MessageConverter messageConverter : messageConverterList) {
            if(messageConverter instanceof MappingJackson2MessageConverter){
                MappingJackson2MessageConverter jackson2MessageConverter = (MappingJackson2MessageConverter) messageConverter;
                ObjectMapper objectMapper = jackson2MessageConverter.getObjectMapper();
                objectMapper.registerModules(new JavaTimeModule());
            }
        }
        return converter;
    }
}
7.1 編寫訊息生產者:
@Slf4j
@Service
public class RocketStorage implements IDataStorage {
  
		@Autowired(required = true)
    private RocketMQTemplate rocketMQTemplate;

		@Value("${rocketMq.topic:blog_notify_sow}")  
    private String topic;

    @Override
    public void store(String value, Integer type, Long timestamp) {
        String message = String.format("%s,%s,%s",value,type,timestamp);
        rocketMQTemplate.convertAndSend(topic,message); //傳送資料
        log.info("RocketMQ|data sent,value: {}, type:{}, timestamp: {}", value, type, timestamp);
    }

    @Override
    public String getType() {
        return "RocketMQ";
    }
}

編寫介面:IDataStorage

/**
 * 資料傳送到Mq裡...
 */
public interface IDataStorage {

    /**
     * persistence data
     *
     * @param value 接收內容
     * @param type  資料型別
     * @param timestamp 當前時間(時間戳)
     */
    void store(String value,Integer type,Long timestamp);

    String getType();

}

在Controller中呼叫介面傳送資料。

@RestController
@RequestMapping("/dataStorage")
public class DataStorageController {

    @Autowired
    private IDataStorage dataStorage;

    @GetMapping
    public Response sendDataStorage(String value){
        dataStorage.store(value,type,System.currentTimeMillis());
        return Response.success();
    }

}
7.2 編寫訊息消費者

編寫一個RocketMq訊息監聽類實現訊息監聽 RocketDataConsumer :

@Service
@Slf4j
@RocketMQMessageListener(consumerGroup = "blog_message",topic = "blog_notify_sow")
public class RocketDataConsumer implements RocketMQListener {

    @PostConstruct
    public void post() {
        log.warn("***** RocketMq Data Consumer Activated");
    }

    @Autowired
    @Qualifier("dataPersist")
    private IDataPersist dataPersist;


    @Override
    public void onMessage(Object o) {
        log.info("RocketMq 接收到的資訊 . . . . . .:{}",o);
        dataPersist.put(o.toString(),1,System.currentTimeMillis());
    }
}
7.3 測試訊息傳送和接收

啟動專案,透過postman呼叫介面:

呼叫介面後,發現介面呼叫成功了。下面我們檢視控制檯訊息消費者是否接收到訊息。

透過上面輸出的訊息可以看到訊息接收成功了。

相關文章