RocketMQ是阿里出的一个纯java的消息队列框架,其它的还有Kafka,Rabbitmq等,网上也有很多他们的对比,优缺点一目了然,国内可能RocketMQ使用居多,因为它抗住了全球最大的流量洪峰双十一,而且运行稳定!
GitHub:github.com/baiyuliang/…
下图为引用网上关于三者的对比情况图:
关于MQ的作用这里也不再讲了,自行Baidu,你会了解更多!如果你是安卓开发同学,那你就把他理解成EventBus吧,哈哈!
使用Docker安装RocketMQ:
你可以不使用docker,直接安装到linux服务器:Linux部署RocketMq,当然,这会相对麻烦一点!
首先,打开Xftp 6软件连接Linux服务器,在usr/local或者其它文件夹下,创建mq文件夹,再在mq文件夹下创建conf和data两个文件夹:
在conf文件夹下新建broker.conf文件,并编辑内容一下内容后保存:
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
brokerIP1 = 39.xxx.x.xx
brokerIP1为你本机的外网地址!
准备就绪后,开始安装:
1.下载:
docker pull rocketmqinc/rocketmq
2.启动rocketmq:
docker run -d -p 9876:9876 -v /usr/local/mq/data/namesrv/logs:/root/logs -v /usr/local/mq/data/namesrv/store:/root/store --name rmqnamesrv -e "MAX_POSSIBLE_HEAP=100000000" rocketmqinc/rocketmq sh mqnamesrv
3.启动broker:
docker run -d -p 10911:10911 -p 10909:10909 -v /usr/local/mq/data/broker/logs:/root/logs -v /usr/local/mq/data/broker/store:/root/store -v /usr/local/mq/conf/broker.conf:/opt/rocketmq/conf/broker.conf --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker autoCreateTopicEnable=true -c /opt/rocketmq/conf/broker.conf
4.安装控制台:
docker pull styletang/rocketmq-console-ng
7.启动控制台:
docker run -e "JAVA_OPTS=-Drocketmq.config.namesrvAddr=39.xxx.x.xx:9876 -Drocketmq.config.isVIPChannel=false" -p 8082:8080 -t styletang/rocketmq-console-ng
注意自己的外网ip地址不要写错,如果你更改了默认的端口映射,那么要注意你的端口保持一致!
浏览器打开:39.xxx.x.xx/8082
你可以在右侧选择中文语言,但到这里并不算成功,点击Cluster/集群:
出现broker-a,即你在broker.conf文件内声明的brokerName时,表明你的RockerMQ完全安装成功了!
整合进项目测试:
pom.xml引入:
<!--消息框架rocketmq-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.1</version>
</dependency>
application.propertites中配置:
spring.application.name=springboottest
#配置项目根路径
server.servlet.context-path=/byl
spring.thymeleaf.cache=false
####RocketMQ相关配置
###producer
#该应用是否启用生产者
rocketmq.producer.isOnOff=on
#发送同一类消息的设置为同一个group
rocketmq.producer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.producer.namesrvAddr=39.xxx.x.xx:9876
#主题
rocketmq.producer.topics=MyTopic;
#消息最大长度 默认1024*128(128M)
rocketmq.producer.maxMessageSize=131027
#发送消息超时时间,默认10000
rocketmq.producer.sendMsgTimeout=10000
#发送消息失败重试次数,默认2
rocketmq.producer.retryTimesWhenSendFailed=2
###consumer
##该应用是否启用消费者
rocketmq.consumer.isOnOff=on
rocketmq.consumer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.consumer.namesrvAddr=39.xxx.x.xx:9876
#该消费者订阅的主题
rocketmq.consumer.topics=MyTopic;
rocketmq.consumer.consumeThreadMin=20
rocketmq.consumer.consumeThreadMax=64
#设置一次消费消息的条数,默认为1条
rocketmq.consumer.consumeMessageBatchMaxSize=1
rocketmq的三大件:Producer,Consumer,MessageListener,分别进行配置:
MQProducerConfig:
package com.byl.springboottest.rocket;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 消息生产者配置
*/
@Configuration
public class MQProducerConfig {
@Value("${rocketmq.producer.groupName}")
private String groupName;
@Value("${rocketmq.producer.namesrvAddr}")
private String namesrvAddr;
@Value("${rocketmq.producer.maxMessageSize}")
private Integer maxMessageSize;
@Value("${rocketmq.producer.sendMsgTimeout}")
private Integer sendMsgTimeout;
@Value("${rocketmq.producer.retryTimesWhenSendFailed}")
private Integer retryTimesWhenSendFailed;
@Bean
public DefaultMQProducer defaultMQProducer() {
DefaultMQProducer producer = new DefaultMQProducer(this.groupName);
producer.setNamesrvAddr(this.namesrvAddr);
producer.setMaxMessageSize(this.maxMessageSize);
producer.setSendMsgTimeout(this.sendMsgTimeout);
producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
try {
producer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
return producer;
}
}
MQConsumerConfig:
package com.byl.springboottest.rocket;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 消费者配置
*/
@Configuration
public class MQConsumerConfig {
@Value("${rocketmq.consumer.namesrvAddr}")
private String namesrvAddr;
@Value("${rocketmq.consumer.groupName}")
private String groupName;
@Value("${rocketmq.consumer.consumeThreadMin}")
private int consumeThreadMin;
@Value("${rocketmq.consumer.consumeThreadMax}")
private int consumeThreadMax;
@Value("${rocketmq.consumer.topics}")
private String topics;
@Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
private int consumeMessageBatchMaxSize;
@Resource
private MQMsgListener mqMsgListener;
@Bean
public DefaultMQPushConsumer defaultMQPushConsumer() {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
consumer.setNamesrvAddr(namesrvAddr);
consumer.setConsumeThreadMin(consumeThreadMin);
consumer.setConsumeThreadMax(consumeThreadMax);
consumer.registerMessageListener(mqMsgListener);
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// consumer.setMessageModel(MessageModel.CLUSTERING);
consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
try {
consumer.subscribe(topics, "MyTag");
consumer.start();
} catch (MQClientException e) {
}
return consumer;
}
}
MQMsgListener:
package com.byl.springboottest.rocket;
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.common.message.MessageExt;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 消息接收监听
*/
@Component
public class MQMsgListener implements MessageListenerConcurrently {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
if (msgs == null || msgs.size() == 0) {
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
MessageExt messageExt = msgs.get(0);
System.out.println("接受到的消息为:" + messageExt.toString());
if (messageExt.getTopic().equals("你的Topic")) {
if (messageExt.getTags().equals("你的Tag")) {
//判断该消息是否重复消费(RocketMQ不保证消息不重复,如果你的业务需要保证严格的不重复消息,需要你自己在业务端去重)
//获取该消息重试次数
int reconsume = messageExt.getReconsumeTimes();
if (reconsume == 3) {//消息已经重试了3次,如果不需要再次消费,则返回成功
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
//处理对应的业务逻辑
}
}
// 如果没有return success ,consumer会重新消费该消息,直到return success
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
打开SpringboottestApplicationTests测试:
@Resource
DefaultMQProducer defaultMQProducer;
@Test
void testSendRocketMq() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
String msg = "rocketmq发送查询消息:查询成功";
Message sendMsg = new Message("MyTopic", "MyTag", msg.getBytes());
//默认3秒超时
SendResult sendResult = defaultMQProducer.send(sendMsg);
SendStatus sendStatus = sendResult.getSendStatus();
System.out.println("消息发送响应信息状态:" + sendStatus);
System.out.println("消息发送响应信息:" + sendResult.toString());
}
运行testSendRocketMq方法:
具体返回内容:
SendResult [sendStatus=SEND_OK, msgId=C0A801184D2818B4AAC27A4996310000, offsetMsgId=2769096000002A9F0000000000000347, messageQueue=MessageQueue [topic=ConsumerTopic, brokerName=broker-a, queueId=2], queueOffset=0]
打开rocketmq控制台:
注意,经测试,在消费者订阅主题时:
subscribe(String topic, String subExpression)
第二个参数,也就是发送消息时设置的Tag,必须指定,如:
consumer.subscribe("MyTopic", "MyTag");
或
consumer.subscribe("MyTopic", "MyTag||MyTag2");
如果设为consumer.subscribe("MyTopic", "*")会导致无法收到消息!