前言
之前我們把RMQ的多Master集羣搭建起來了,我們今天就來看看如何向這個集羣生產消息以及消費消息。
集羣搭建回顧
回顧上節的內容,我總結下以下幾步:
第一:最新版RMQ4.2.0要求最低JDK8版本
第二:修改虛擬機的host,配置nameserver域名
第三:安裝RMQ
第四:新建RMQ的消息存儲文件
第五:修改RMQ的日誌輸出
第六:配置Broker配置文件
第七:根據虛擬機實際情況修改runserver.sh和runbroker.sh啓動參數
第八:啓動nameserver再啓動broker
第九:生成控制檯
OK,我們再來看下集羣結果:
JAVA操作RMQ
第一步:POM引入相關jar
根據GitHub上的quickstart,我直接將我們將來需要用到的jar都導入進來了(你其實只需要導入):
<parent>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-all</artifactId>
<version>4.2.0</version>
</parent>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-client</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-srvutil</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>io.openmessaging</groupId>
<artifactId>openmessaging-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-openmessaging</artifactId>
<version>4.2.0</version>
第二步:生產者Producer
public class Producer {
public static void main(String[] args) throws MQClientException, InterruptedException {
// 聲明一個生產者,需要一個自定義生產者組(後面我們會介紹這個組的概念和作用)
DefaultMQProducer producer = new DefaultMQProducer("myTestGroup");
// 設置集羣的NameServer地址,多個地址之間以分號分隔
producer.setNamesrvAddr("139.196.184.3:9876;139.196.51.36:9876");
// 啓動生產者實例
producer.start();
// 模擬發送100條消息 到Topic爲TopicTest,tag爲tagA,消息內容爲Hello RocketMQ +i
for (int i = 0; i < 100; i++) {
try {
Message msg = new Message("TopicTest" ,"TagA",("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
);
// 調用Produce的send方法發送消息
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
} catch (Exception e) {
e.printStackTrace();
Thread.sleep(1000);
}
}
// 發送完消息之後調用producer的shutdown()方法關閉producer
producer.shutdown();
}
}
第三步:消費者Consumer
public class Consumer {
public static void main(String[] args) throws Exception {
// 聲明一個消費者consumer,需要傳入一個組
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerTest");
// 設置集羣的NameServer地址,多個地址之間以分號分隔
consumer.setNamesrvAddr("139.196.184.3:9876;139.196.51.36:9876");
// 設置consumer的消費策略
// CONSUME_FROM_LAST_OFFSET 默認策略,從該隊列最尾開始消費,即跳過歷史消息
// CONSUME_FROM_FIRST_OFFSET 從隊列最開始開始消費,即歷史消息(還儲存在broker的)全部消費一遍
// CONSUME_FROM_TIMESTAMP 從某個時間點開始消費,和setConsumeTimestamp()配合使用,默認是半個小時以前
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
// 設置consumer所訂閱的Topic和Tag,*代表全部的Tag
consumer.subscribe("TopicTest", "*");
// Listener,主要進行消息的邏輯處理,監聽topic,如果有消息就會立即去消費
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
// 返回消費狀態 有2種狀態 CONSUME_SUCCESS 消費成功 RECONSUME_LATER 消費失敗,需要稍後重新消費
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 調用start()方法啓動consumer
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
OK,現在我們啓動消費者,注意一定是要先啓動消費者,後啓動生產者,這點很好理解,消費者得先訂閱,生產者再生產消息,訂閱之後就能消費消息,當然如果你非要先啓動生產者也行,但是這會有一些問題,會導致有可能消息被重複消費(這點後面我會詳細講解),主要原因是RMQ是通過消費返回消息的狀態來判斷一條消息是否被消費,如果你先啓動生產者,就會造成可能第一個consumer1拿到消息A,還沒返回狀態時,consumer2也拿到了消息A,就會造成重複消費,所以,儘量避免有消息堆積造成消息重複消費,這些我們後面會詳細講,今天主要講入門,如何玩成一個生產消費的過程。下面我們來看看這個demo的結果:
producer端(細心的小夥伴會發現生產者怎麼是4個一組4個一組的發的,這裏先賣個關子):
consumer端:consumer端是一直啓動的,監聽這它所訂閱的主題,一旦有消息就會去處理
我們再來看看控制檯:我是生產了2次100,就就是200條消息,也看到這200條102條落到broker-a上98條落到broker-b上,從這裏也證實了生產者是4個消息一組發送的,所以纔會出現102+98的結果:
這裏就是我們的消費者訂閱的主題:可以點詳情進去看的,這個控制檯其實還是不錯的
結束
OK,RMQ的入門就介紹到這裏了,上面賣的關子我還是忍不住想告訴你,其實這個是我們在配置broker時可以指定的,這裏我把Broker配置文件詳細的貼一份給小夥伴們吧,小夥伴們做下相應的修改就能使用了:
brokerClusterName=rocketmq-cluster-justin
brokerName=broker-a
brokerId=0
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#在發送消息時,自動創建服務器不存在的topic,默認創建的隊列數
defaultTopicQueueNums=4
#是否允許 roker 自動創建Topic,建議線下開啓,線上關閉
autoCreateTopicEnable=true
#是否允許 Broker 自動創建訂閱組,建議線下開啓,線上關閉
autoCreateSubscriptionGroup=true
#Broker對外服務的監聽端口
listenPort=10911
#刪除文件時間點,默認凌晨4點
deleteWhen=04
#文件保留時間,默認48 小時
fileReservedTime=120
#commitLog每個文件的大小默認1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每個文件默認存30W條,根據業務情況調整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#檢測物理文件磁盤空間
diskMaxUsedSpaceRatio=88
#存儲路徑
storePathRootDir=/usr/local/rocketmq/store
#commitLog存儲路徑
storePathCommitLog=/usr/local/rocketmq/store/commitlog
#消費隊列存儲路徑存儲路徑
storePathConsumeQueue=/usr/local/rocketmq/store/consumequeue
#消息索引存儲路徑
storePathIndex=/usr/local/rocketmq/store/index
#checkpoint文件存儲路徑
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
#abort文件存儲路徑
abortFile=/usr/local/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker的角色
#- ASYNC_MASTER 異步複製Master
#- SYNC_MASTER 同步雙寫Master
#- SLAVE
brokerRole=ASYNC_MASTER
#刷盤方式
#- ASYNC_FLUSH 異步刷盤
#- SYNC_FLUSH 同步刷盤
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false