阿里RocketMq試用記錄+簡單的Spring整合

架構師springboot發表於2019-03-21

RocketMq試用+簡單的Spring整合

經過2天的試用初步瞭解了一下RocketMq的基本用法,搜尋了一下度娘,沒有找到Spring的例子,所以簡單搞了一點程式碼感受一下。

1.RocketMq

RocketMQ的前身是Metaq,當Metaq3.0釋出時,產品名稱改為RocketMQ,有以下特點: 1) 能夠保證嚴格的訊息順序 2) 提供豐富的訊息拉取模式 3) 高效的訂閱者水平擴充套件能力 4)實時的訊息訂閱機制 5)億級訊息堆積能力 

2.核心原理

2.1. 資料結構

RocketMq
這裡寫圖片描述

(1)所有資料單獨儲存到commit Log ,完全順序寫,隨機讀
(2)對終端使用者展現的佇列實際只儲存訊息在Commit Log 的位置資訊,並且序列方式刷盤
(3)按照MessageId查詢訊息 

è¿éåå¾çæè¿°

(4)根據查詢的key的hashcode%slotNum得到具體的槽位置 

è¿éåå¾çæè¿°

(5)根據slotValue(slot對應位置的值)查詢到索引項列表的最後一項
(6)遍歷索引項列表返回查詢時間範圍內的結果集

2.2. 刷盤策略

rocketmq中的所有訊息都是持久化的,先寫入系統pagecache,然後刷盤,可以保證記憶體與磁碟都有一份資料,訪問時,可以直接從記憶體讀取

使用簡單的符號標識不同的標題,將某些文字標記為粗體或者

斜體

,建立一個連結等,詳細語法參考幫助?。

本編輯器支援 Markdown Extra ,  擴充套件了很多好用的功能。具體請參考[Github][2].

2.3. 記憶體機制

è¿éåå¾çæè¿°

2.4. 工作模式

è¿éåå¾çæè¿°

3. 環境安裝

3.1. JAVA環境安裝

安裝

rpm -ivh jdk-7u80-linux-x64.rpm

環境變數

JAVA_HOME=/usr/java/jdk1.7.0_80 CLASSPATH=.:$JAVA_HOME/lib.tools.jar PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME CLASSPATH PATH export ROCKETMQ_HOME=/usr/local/service/alibaba-rocketmq

3.2. RocketMq安裝

https://github.com/alibaba/RocketMQ/releases下載3.2.6,解壓 

4. 測試網路拓撲

è¿éåå¾çæè¿°

因為手裡沒有其他伺服器,105那臺缺少一個slave,在同步雙寫模式下,傳送訊息會返回 SLAVE_NOT_AVAILABLE,不過訊息已經傳送成功,只是slave沒有寫成功。

5. 啟停操作

這裡只給出一個基本的示例,各個模式的啟停在本文最後的參考文獻中會有詳細的說明。這裡不再贅述。 
  • 啟動nameserver

nohup ./mqnamesrv &複製程式碼
  • 停止nameServer

./mqshutdown namesrv複製程式碼
  • 啟動broker(單master)(多master,多master+slave)對應的(非同步複製,同步雙寫)
  • nohup sh mqbroker -n 192.168.146.109:9876 -c $ROCKETMQ_HOME/conf/2m-noslave/broker-a.properties &複製程式碼
  • 停止broker

./mqshutdown broker複製程式碼

6. 運維指令

  • 檢視叢集情況
./mqadmin clusterList -n 127.0.0.1:9876複製程式碼
  • 檢視broker狀態
./mqadmin brokerStatus -n 127.0.0.1:9876 -b 192.168.146.105:109111複製程式碼
  • 檢視topic列表
./mqadmin topicList -n 127.0.0.1:98761複製程式碼
  • 檢視topic狀態
./mqadmin topicStatus -n 127.0.0.1:9876 -t PushTopic複製程式碼
  • 檢視topic路由
./mqadmin topicRoute  -n 127.0.0.1:9876 -t PushTopic
複製程式碼

7. 基本測試

基本測試採用java直接編碼的方式生產和消費訊息,例子來源於參考文獻的《RocketMQ開發教程》。本文最後的程式碼示例,採用了spring的形式。

  • Producer

package com.jd.wxz;

import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;

public class Producer {
    public static void main(String[] args){
        DefaultMQProducer producer = new DefaultMQProducer("Producer");
        producer.setNamesrvAddr("192.168.146.109:9876"); 
        try {
            producer.start();

            Message msg = new Message("PushTopic", 
                    "push", 
                    "1", 
                    "Just for test.".getBytes());

            SendResult result = producer.send(msg);
            System.out.println("id:" + result.getMsgId() +
                    " result:" + result.getSendStatus());

            msg = new Message("PushTopic", 
                    "push", 
                    "2", 
                    "Just for test.".getBytes());

            result = producer.send(msg);
            System.out.println("id:" + result.getMsgId() +
                    " result:" + result.getSendStatus());

            msg = new Message("PullTopic", 
                    "pull", 
                    "1", 
                    "Just for test.".getBytes());

            result = producer.send(msg);
            System.out.println("id:" + result.getMsgId() +
                    " result:" + result.getSendStatus());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            producer.shutdown();
        }
    }
}
複製程式碼

  • Consumer

package com.sean;

import java.util.List;

import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere;
import com.alibaba.rocketmq.common.message.Message;
import com.alibaba.rocketmq.common.message.MessageExt;

public class Consumer {
    public static void main(String[] args){
        DefaultMQPushConsumer consumer = 
                new DefaultMQPushConsumer("PushConsumer");
        consumer.setNamesrvAddr("192.168.146.109:9876"); 
        try {
            //訂閱PushTopic下Tag為push的訊息
            consumer.subscribe("PushTopic", "push");
            //程式第一次啟動從訊息佇列頭取資料
            consumer.setConsumeFromWhere(
                    ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
            consumer.registerMessageListener(
                new MessageListenerConcurrently() {
                    public ConsumeConcurrentlyStatus consumeMessage(
                            List<MessageExt> list,
                            ConsumeConcurrentlyContext Context) {
                        Message msg = list.get(0);
                        System.out.println(msg.toString());
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    }
                }
            );
            consumer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

執行結果: 

è¿éåå¾çæè¿°

è¿éåå¾çæè¿°

服務端監控: 

è¿éåå¾çæè¿°

8.當機實驗

è¿éåå¾çæè¿°

9.遺留問題

1)  關閉master 自動切換到slave無法實現,官方資料上沒有明確指明,第三方文件裡有(見文獻3)。
2)  在開發機伺服器上執行os.sh進行優化,導致網路無法連線,運維幫忙重啟才恢復。
複製程式碼

技術的提升是需要下苦工,需要堅持不懈的努力。就比如下面的分享的這些技術點,是否都學會並掌握了呢?如需要以下圖譜以及跟多提升架構技術的資源可加入我的粉絲Qqun:855801563。我花了將近一個月時間蒐集整理了一套架構技術提升知識點講解以及一些面試題解析和答案免費分享給大家。助力各位程式設計師朋友突破自我提升技能,實現自己的目標。

相關文章