springBoot+RocketMQ 示例
創建 springboot 項目或者在自己的項目中的 pom 文件中引入依賴
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot</artifactId>
<version>2.2.0</version>
</dependency>
引入依賴之后我們需要配置一下 rocketmq 的配置信息,打開我們的 application.yml
rocketmq:
name-server: 8.***.***.**:9876; #nameserver IP地址
producer:
group: TEST_GROUP # 指定group
send-message-timeout: 3000 # 消息發送超時時長,默認3s
retry-times-when-send-failed: 3 # 同步發送消息失敗重試次數,默認2
retry-times-when-send-async-failed: 3 # 異步發送消息失敗重試次數,默認2
定義生產者
首先自定義一個生產者。用來投遞消息。
@Slf4j
@Component
public class MQProducerService {
// 直接注入使用,用于發送消息到broker服務器
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 普通發送
*/
public void send(String body,String topic) {
rocketMQTemplate.convertAndSend(topic , body);
// rocketMQTemplate.send(topic + ":tag1", MessageBuilder.withPayload(user).build()); // 等價于上面一行
}
/**
* 發送同步消息(阻塞當前線程,等待broker響應發送結果,這樣不太容易丟失消息)
* (msgBody也可以是對象,sendResult為返回的發送結果)
*/
public SendResult sendMsg(String body,String topic) {
SendResult sendResult = rocketMQTemplate.syncSend(topic, MessageBuilder.withPayload(body).build());
log.info("【sendMsg】sendResult={}", JSON.toJSONString(sendResult));
return sendResult;
}
/**
* 發送異步消息(通過線程池執行發送到broker的消息任務,執行完后回調:在SendCallback中可處理相關成功失敗時的邏輯)
* (適合對響應時間敏感的業務場景)
*/
public void sendAsyncMsg(String body,String topic) {
rocketMQTemplate.asyncSend(topic, MessageBuilder.withPayload(body).build(), new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
//發送成功處理...
}
@Override
public void onException(Throwable throwable) {
//發送失敗處理...
}
});
}
/**
* 發送延時消息(上面的發送同步消息,delayLevel的值就為0,因為不延時)
* 在start版本中 延時消息一共分為18個等級分別為:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
*/
public void sendDelayMsg(String body,String topic, int delayLevel) {
rocketMQTemplate.syncSend(topic, MessageBuilder.withPayload(body).build(), 3000, delayLevel);
}
/**
* 發送單向消息(只負責發送消息,不等待應答,不關心發送結果,如日志)
*/
public void sendOneWayMsg(String body,String topic) {
rocketMQTemplate.sendOneWay(topic, MessageBuilder.withPayload(body).build());
}
/**
* 發送帶tag的消息,直接在topic后面加上":tag"
*/
public SendResult sendTagMsg(String body,String topic) {
return rocketMQTemplate.syncSend(topic, MessageBuilder.withPayload(body).build());
}
}
代碼中 body 就是消息體,如果你發消息之前是一個/一組對象,可以轉換成 json 格式,當然也可以把上面的 body 修改成自己要傳的對象比如 User。 topic 就是要發送到那個主題上。
public void sendOneWayMsg(User user,String topic) {
rocketMQTemplate.sendOneWay(topic, MessageBuilder.withPayload(user).build());
}
上面就是一個 Producer 示例,里面包含了多種發送消息的模式,當然 RocketMQ 給我們提供的不止這些,大家可以去官方文檔看一下。
定義消費者
@Slf4j
// MessageExt:是一個消息接收通配符,不管發送的是String還是對象,都可接收,當然也可以像上面明確指定類型(我建議還是指定類型較方便)
//,messageModel = MessageModel.BROADCASTING
@Service
@RocketMQMessageListener(topic = "TEST_TOPIC", consumerGroup = "TEST_Group")
public class TaxInfoConsumerService implements RocketMQListener<MessageExt> {
@Override
public void onMessage(MessageExt message) {
System.out.println("線程" + Thread.currentThread() + "內容為:"
+ new String(message.getBody()) +
"隊列序號:" + message.getQueueId());
//這里消費的消息可以寫自己的業務邏輯代碼,比如插入,刪除,上傳。。。
}
這個就是簡單的消費者示例。
@RocketMQMessageListener(topic = "TEST_TOPIC", consumerGroup = "Test_Group")
這行代碼表示當前消費者監聽了 TEST_TOPIC 上的信息,消費者組的名字就叫做 Test_Group. 如果有生產者往 TEST_TOPIC 上投遞消息,就會被當前消費者感知,并且去消費指定 Topic 上的信息。
發送消息
//使用之前先注入我們剛創建的MQProducerService
@Inject
private MQProducerService mqProducerService;
......
//我自己有一個類TaxInfoBean,里面封裝了我要傳的數據:
TaxInfoBean taxInfoBean = new TaxInfoBean();
taxInfoBean.setSn(taxInfoSn.nextNo());
taxInfoBean.setOutTxNo(outTxNo);
taxInfoBean.setNotifyTimes(0);
taxInfoBean.setAmount(amount);
taxInfoBean.setIdCardNo(idCardNo);
taxInfoBean.setTaxNo(taxNo);
taxInfoBean.setInvoiceCode(invoiceCode);
taxInfoBean.setBankReceiptFiles(bankReceiptFiles);
taxInfoBean.setProofFiles(proofFiles);
taxInfoBean.setTaxProjectName(taxProjectName);
String taxInfoData = JSON.toJSONString(taxInfoBean);
//重點:使用剛剛創建的mqProducerService的異步發送方式發送消息。
//taxinfoData是投遞的消息,TEST_TOPIC代表我要投遞到這個topic中
mqProducerService.sendAsyncMsg(taxInfoData, “TEST_TOPIC”);
大家可以自己創建一個測試類,測試一下,我這里只截取了部分代碼。
啟動測試方法,發送消息,我們打開控制臺就會看到輸出了:
線 程 Thread[ConsumeMessageThread_14,5,main]內 容 為 :
{
"amount":999.99,
"idCardNo":"410425128710026151",
"invoiceCode":"304990000123400000001014",
"invoiceType":1,
"notifyTimes":0,
"outTxNo":"BZD44V5Dh_V_vQ7h9fEXa",
"settlementType":0,
"sn":"1123041202077",
"taskStatus":"PROCESSING",
"taxNo":"91110105MA01R54K8A2",
"taxProjectName":"20230491110105MA01R54K8A2"
}
隊 列 序 號 :8
沒錯,這就是消費者已經成功消費了,并把整個 message 打印了出來,我們的消息內容是 message.getBody()的所有內容。
我們可以在消費者里面加上自己業務代碼。
springboot+rocketmq 單機部署(centos7+docker)
想了一下還是跟大家一起用 docker 先單機部署一下 熟悉流程之后,后面的集群部署也就非常簡單了。
首先打開我們的 Linux 環境,啟動 docker(沒有安裝 docker 的可以搜一下,直接安裝就行。)
啟動 doker: systemctl start docker
搜索鏡像
docker search rocketmq
拉取鏡像
docker pull rocketmqinc/rocketmq
一般情況下拉取的就是最新版本。
這個時候 rocketmq 已經準備好了,我們回憶下上一節的啟動過程,這里有些類似的地方,我們創建一個存放 nameserver 的數據目錄:
mkdir -p /docker/rocketmq/nameserver/logs /docker/rocketmq/nameserver/store
同理,我們也提前創建存放 broker 配置信息目錄,我們需要單獨創建一個存放 broker 配置信息的文件目錄
mkdir -p /docker/rocketmq/data/broker-master/confmkdir -p /docker/rocketmq/data/broker-slave/conf
能看出來,這兩個文件夾就是代表 broker 的一主一從。除了這個 conf 文件夾,我們還要另外創建兩個文件夾
一主一從: 前面大家都知道了 broker 可以配置主從節點,一個 master 一個 slave,master 節點會進行異步/同步刷盤到 slave 上,這也保證了如果某個 broker 掛了,slave 能夠迅速頂上。
RocketMQ 支持兩種刷盤方式:同步刷盤和異步刷盤。同步刷盤是指在消息發送的同時將消息寫入磁盤,確保消息不會丟失,但是會降低消息發送的速度。異步刷盤是指將消息先寫入內存緩存,然后再定時或者觸發條件下將緩存中的消息寫入磁盤,這樣可以提高消息發送的速度,但是可能會造成消息丟失的風險。
mkdir -p /docker/rocketmq/data/broker-master/store
mkdir -p /docker/rocketmq/data/broker-master/logs
mkdir -p /docker/rocketmq/data/broker-slave/store
mkdir -p /docker/rocketmq/data/broker-slave/logs
整體的架構就是:
? docker/rockermq
.
├── data
│ ├── broker-master
│ ├── conf
│ ├── store
│ └── logs
│ ├── beoker-slave
│ ├── conf
│ ├── store
│ └── logs
└── nameserver
├── store
└── logs
初始的文件夾已經創建好了,我們要先啟動 nameserver.
docker run -d --restart=always --name rmqnamesrv --privileged=true -p 9876:9876 -v /docker/rocketmq/nameserver/logs:/root/logs -v /docker/rocketmq/nameserver/store:/root/store -e "MAX_POSSIBLE_HEAP=100000000" rocketmqinc/rocketmq sh mqnamesrv
參數說明
[圖片上傳失敗...(image-723cc7-1688441580784)]
配置 broker
我們有關 broker 的文件夾之前已經創建好了,但是缺少配置文件 broker.conf
創建 master 的 broker.conf
brokerName = brokera-master
brokerId = 0 #id為0代表當前是主節點(master)
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876; #你的nameserver地址
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false #這個強烈建議設置成false
brokerIP1 = 當前服務器ip地址
然后把這個文件放到 data/broker-master/conf 里面
創建 slave 的 broker.conf
brokerName = brokera-slave
brokerId = 1
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876;
brokerRole = SLAVE
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false
brokerIP1 = 當前服務器ip地址
然后把這個文件放到 data/broker-slave/conf 里面
autoCreateTopicEnable 代表是否開啟自動創建 topic,這里大家設置成 false 就行,如果只是自己測試一下那就無所謂,發不到線上的話為了避免創建無用的 topic,浪費資源,建議還是關掉。
整體目錄架構
? docker/rockermq
.
├── data
│ ├── broker-master
│ ├── conf
│ ├──broker.conf
│ ├── store
│ └── logs
│ ├── beoker-slave
│ ├── conf
│ ├──broker.conf
│ ├── store
│ └── logs
└── nameserver
├── store
└── logs
啟動 broker
這里大家一定要謹慎,這里最容易出錯,大家啟動的時候一定提前看看自己的命令是否正確 我們要啟動兩次 broker(一主一從) 啟動 brokera-master
docker run -d --restart=always --name brokera-master --link rmqnamesrv:namesrv -p 10911:10911 -p 10909:10909 --privileged=true -v /docker/rocketmq/data/broker-master/logs:/root/logs -v /docker/rocketmq/data/broker-master/store:/root/store -v /docker/rocketmq/data/broker-master/conf/broker.conf:/opt/docker/rocketmq/data/broker-master/conf/broker.conf -e "NAMESRV_ADDR=8.***:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-master/conf/broker.conf
大家把 NAMESRV_ADDR=8.*:9876",改成自己的 nameserver 地址。
如果前面的所有步驟都跟我的一樣,正常情況下是沒問題的,如果前面創建文件夾那里并沒有跟我的一模一樣,那你就要把命令改一下,文件目錄做一下修改才行。
完事之后輸入
docker ps -a 查看所有的已經啟動的容器。
可以看到 STATUS 那里是啟動成功的 那么 master 節點的 broker 就已經啟動成功了,接下來啟動 slave
docker run -d --restart=always --name brokera-slave --link rmqnamesrv:namesrv -p 10124:10911 -p 10623:10909 --privileged=true -v /docker/rocketmq/data/broker-slave/logs:/root/logs -v /docker/rocketmq/data/broker-slave/store:/root/store -v /docker/rocketmq/data/broker-slave/conf/broker.conf:/opt/docker/rocketmq/data/broker-slave/conf/broker.conf -e "NAMESRV_ADDR=8.*:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-slave/conf/broker.conf
把 NAMESRV_ADDR 的地址換成自己的 nameserver 地址。
可以看到一主一從都已經啟動成功了
安裝可視化控制臺
啟動完 broker 和 nameserver 之后,我們啟動可視化控制臺。
拉取鏡像
docker pull pangliang/rocketmq-console-ng
直接啟動控制臺 啟動之前大家把 nameserv.addr 的地址改成自己的 nameserver 的 IP 地址
docker run -d --restart=always --name rmqadmin -e "JAVA_OPTS=-Drocketmq.namesrv.addr=122.*.*.*:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 pangliang/rocketmq-console-ng
完事之后直接打開服務器 ip:8080 直接啟動就能看到熟悉的頁面
可以看到一主一從,我的名字是 brokera-master-a,brokera-slave-a
如果沒有這兩條 broker 記錄大家一定要檢查自己的 nameserver 地址有沒有配置,著重檢查 broker.conf,和啟動容器命令,容器命令有多個文件目錄,一定要跟自己創建的對的上。
springboot 使用
整合 Springboot 和上面的過程一模一樣 ,application.yml 的 namesrv-addr 可能要改成自己 Linux 配置之后的地址, 其他代碼不用改。
springboot+rocketmq 集群部署(centos7+docker)
趁熱打鐵,上面完成了單機部署,我這里有兩臺服務器,我采用的是 2 個 nameserver,broker 是 2 主 2 從。 每臺服務器上是 1 個 nameserver 和 broker(一主一從)
我們按照上面的步驟每臺服務器上都重復創建好存放 nameserver 和 broker 的文件目錄,兩臺服務器都是如此
? docker/rockermq
.
├── data
│ ├── broker-master
│ ├── conf
│ ├──broker.conf
│ ├── store
│ └── logs
│ ├── beoker-slave
│ ├── conf
│ ├──broker.conf
│ ├── store
│ └── logs
└── nameserver
├── store
└── logs
兩臺服務器都拉取 rocketmq 鏡像,然后依次啟動容器(兩臺服務器命令一樣)
docker run -d --restart=always --name rmqnamesrv --privileged=true -p 9876:9876 -v /docker/rocketmq/nameserver/logs:/root/logs -v /docker/rocketmq/nameserver/store:/root/store -e "MAX_POSSIBLE_HEAP=100000000" rocketmqinc/rocketmq sh mqnamesrv
這樣就啟動了 2 臺 nameserver
接下來配置 broker.conf
第一臺服務器上的一主一從 broker.conf
brokerClusterName = XgshDefaultCluster
brokerName = broker-master-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876;8.*.*.*:9876 #大家可以看到這里有兩個nameserver IP地址,用分號隔開。
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false #關閉自動創建Topic
brokerIP1 = 本機服務器IP
brokerClusterName = XgshDefaultCluster
brokerName = broker-slave-a
brokerId = 1
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876;8.*.*.*:9876
brokerRole = SLAVE
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false
brokerIP1 = 本機服務器IP
第二臺服務器上的一主一從 broker.conf
brokerClusterName = XgshDefaultCluster
brokerName = broker-master-b
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876;8.*.*.*:9876 #大家可以看到這里有兩個nameserver IP地址,用分號隔開。
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false
brokerIP1 = 本機服務器IP
brokerClusterName = XgshDefaultCluster
brokerName = broker-slave-b
brokerId = 1
deleteWhen = 04
fileReservedTime = 48
namesrvAddr = 8.*.*.*:9876;8.*.*.*:9876 #大家可以看到這里有兩個nameserver IP地址,用分號隔開。
brokerRole = SLAVE
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = false
brokerIP1 = 本機服務器IP
參數說明
[圖片上傳失敗...(image-f0dbc-1688441580784)]
啟動 broker
第一臺服務器(命令中的 NAMESRV_ADDR 改成自己服務器啟動的 2 個,中間用分號隔開)
docker run -d --restart=always --name broker-master01 --link rmqnamesrv:namesrv -p 10911:10911 -p 10909:10909 --privileged=true -v /docker/rocketmq/data/broker-master/logs:/root/logs -v /docker/rocketmq/data/broker-master/store:/root/store -v /docker/rocketmq/data/broker-master/conf/broker.conf:/opt/docker/rocketmq/data/broker-master/conf/broker.conf -e "NAMESRV_ADDR=8.*.*.*:9876;8.*.*.*:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-master/conf/broker.conf
docker run -d --restart=always --name broker-slave01 --link rmqnamesrv:namesrv -p 10124:10911 -p 10623:10909 --privileged=true -v /docker/rocketmq/data/broker-slave/logs:/root/logs -v /docker/rocketmq/data/broker-slave/store:/root/store -v /docker/rocketmq/data/broker-slave/conf/broker.conf:/opt/docker/rocketmq/data/broker-slave/conf/broker.conf -e "NAMESRV_ADDR=8.*.*.*:9876;8.*.*.*:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-slave/conf/broker.conf
第二臺服務器(命令中的 NAMESRV_ADDR 改成自己服務器啟動的 2 個,中間用分號隔開)
docker run -d --restart=always --name broker-master02 --link rmqnamesrv:namesrv -p 10911:10911 -p 10909:10909 --privileged=true -v /docker/rocketmq/data/broker-master/logs:/root/logs -v /docker/rocketmq/data/broker-master/store:/root/store -v /docker/rocketmq/data/broker-master/conf/broker.conf:/opt/docker/rocketmq/data/broker-master/conf/broker.conf -e "NAMESRV_ADDR=8.*.*.*:9876;8.*.*.*:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-master/conf/broker.conf
docker run -d --restart=always --name broker-slave02 --link rmqnamesrv:namesrv -p 10124:10911 -p 10623:10909 --privileged=true -v /docker/rocketmq/data/broker-slave/logs:/root/logs -v /docker/rocketmq/data/broker-slave/store:/root/store -v /docker/rocketmq/data/broker-slave/conf/broker.conf:/opt/docker/rocketmq/data/broker-slave/conf/broker.conf -e "NAMESRV_ADDR=8.*.*.*:9876;8.*.*.*:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker -c /opt/docker/rocketmq/data/broker-slave/conf/broker.conf
broker 啟動成功,我們通過命令看一下(2 臺服務器都看一下)
docker ps -a
第一臺服務器:
第二臺服務器:
大家看一下 STATUS 是都啟動成功。
啟動控制臺
在其中一臺服務器拉取可視化界面鏡像(只用在其中一臺啟動就可以了)
docker run -d --restart=always --name rmqadmin -e "JAVA_OPTS=-Drocketmq.namesrv.addr=122.*.*.*:9876;122.*.*.*:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 pangliang/rocketmq-console-ng
訪問服務器 IP:8080 能看到下面的就代表成功了!!
整合 springboot
我們只需要在 applicatiom.yml 文件中修改為 2 個 nameserver 地址用分號隔開
rocketmq:
name-server: 8.*.*.*:9876;8.*.*.*:9876 # 兩個nameserver訪問地址
producer:
group: Pro_Group # 必須指定group
send-message-timeout: 3000 # 消息發送超時時長,默認3s
retry-times-when-send-failed: 3 # 同步發送消息失敗重試次數,默認2
retry-times-when-send-async-failed: 3 # 異步發送消息失敗重試次數,默認2
啟動項目,我們根據自己的需要去創建 Topic,然后通過開篇的示例去發送消息到消費者消費消息過程是不變的。
問題:
1.可視化界面一直加載不出來
2.因為我用的是阿里云服務器,所以訪問不了大概率是 8080 這個端口號沒有加安全組,大家進入到阿里云找到服務器,添加安全組,端口號 8080,建議大家設置一下授權對象,然后把自己本機 ip 輸入進去,返回瀏覽器刷新。就能訪問了。
3.老問題,(2 主 2 從)broker 不顯示
4.首先我們使用 docker ps -a 查看所有啟動的容器,大家可以看下自己啟動的 broker,看一下 STATUS 如果不是 Up 6 hours 這種的,而是很長一串,那就是 broker 啟動失敗了,還是一定要看啟動命令和 broker.conf 每一行配置是否正確,nameserver 地址是否正確!