一.大致了解MQ是什么
MQ即消息队列 ,是一种提供消息队列服务的中间件,也称为消息中间件,是一套提供了消息生 产、存储、消费全过程的软件系统,遵循FIFO原则。
如图用户进行在王者里面进行购买点卷请求,王者给微信发送购买支付请求,王者等待微信那边返回支付成功的消息,而用户又处在一个等待的状态,不能进行游戏的步骤,下一个用户要进行购买点卷要等待前一个用户完成购买的操作之后在进行操作,所有问题会导致消息的堆积和等待时间的过长
RocketMQ的作用就好比是中间商的作用,王者荣耀把购买消息给MQ,MQ放回给王者接受到消息,MQ把购买消息给进行给微信进行操作,当微信把结果返回MQ而不是王者,这样所有的用户消息等待都在MQ里面进行,而不是在客户端进行,等待时间缩短
二.解剖RocketMQ的结构原理
Producer:消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
Consumer:消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。
Broker Server:存储消息的服务,在MQ启动的时候会进行把Message消息进行注册到nameserver
Topic:表示的是一类消息的集合第,每个Topic有多个Message,但一个Message对应一个Topic
MessageQueue:队列的模式,最后存储数据的地方
nameserver:
是一个Broker与Topic路由的注册中心支持Broker的动态注册与发现,主要包括两个功能
- Broker管理
NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活。
- 路由信息管理
每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费
三.安装与使用
下载地址:http://rocketmq.apache.org/release_notes/release-notes-4.2.0/
下载之后进行解压
- Bin : 可执行文件目录
- Conif:配置文件目录
- Lib : 依赖库,一堆Jar包
本地相关的配置
A-配置ROCKETMQ_HOME本地变量
启动NameServer和Broker
Cmd命令框执行进入至MQ文件夹\bin
下,然后执行 start mqnamesrv.cmd
,启动NameServer。
引入Mq的插件
下载地址:RocketMQ可视化管理插件下载地址:Releases · apache/rocketmq-externals · GitHub
下载完成之后进行配置的修改
在进行直接打包使用即可
以SpringBoot搭建的项目整合使用
A-导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
B-启动类
@SpringBootApplication
public class ApplicationStart {
public static void main(String[] args) {
SpringApplication.run(ApplicationStart.class);
}
}
C-配置文件
rocketmq:
name-server: 127.0.0.1:9876
# 是否开启自动配置
producer:
# 发送同一类消息设置为同一个group,保证唯一默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标识
group: "service-pay-producer"
# 消息最大长度 默认 1024 * 4 (4M)
max-message-size: 4096
# 发送消息超时时间,默认 3000
send-message-timeout: 3000
# 发送消息失败重试次数,默认2
retry-times-when-send-failed: 2
retry-times-when-send-async-failed: 2
D-生产者
@Service
public class RocketMQProducer{
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Value("${rocketmq.producer.send-message-timeout}")
private Integer messageTimeOut;
/**
* 发送普通消息
* @return
*/
public SendResult sendMsg(String msgBody){
SendResult result = rocketMQTemplate.syncSend("queue_test_topic", MessageBuilder.withPayload(msgBody).build());
return result;
}
/**
* 发送异步消息 在SendCallback中可处理相关成功失败时的逻辑
*/
public void sendAsyncMsg(String msgBody){
rocketMQTemplate.asyncSend("queue_test_topic",MessageBuilder.withPayload(msgBody).build(), new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 处理消息发送成功逻辑
}
@Override
public void onException(Throwable e) {
// 处理消息发送异常逻辑
}
});
}
/**
* 发送延时消息<br/>
* 在start版本中 延时消息一共分为18个等级分别为:1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h<br/>
*/
public void sendDelayMsg(String msgBody, Integer delayLevel){
rocketMQTemplate.syncSend("queue_test_topic",MessageBuilder.withPayload(msgBody).build(),messageTimeOut,delayLevel);
}
/**
* 发送带tag的消息,直接在topic后面加上":tag"
*/
public void sendTagMsg(String msgBody){
rocketMQTemplate.syncSend("queue_test_topic:tag1",MessageBuilder.withPayload(msgBody).build());
}
}
E-消费者
/**
* rocketmq 消息监听,@RocketMQMessageListener中的selectorExpression为tag,默认为*
*/
@Slf4j
@Component
@RocketMQMessageListener(topic = "queue_test_topic",selectorExpression="*",consumerGroup = "queue_group_test")
public class RocketMQMsgListener implements RocketMQListener<MessageExt> {
@Override
public void onMessage(MessageExt message) {
byte[] body = message.getBody();
String msg = new String(body, CharsetUtil.UTF_8);
log.info("接收到消息:{}", msg);
}
}
F-测试
@Controller
public class ProducerController {
@Autowired
private RocketMQProducer rocketMQProducer;
@RequestMapping("/send")
@ResponseBody
public SendResult send(String msg) {
//formats: `topicName:tags`
return rocketMQProducer.sendMsg(msg);
}
}
事务消息的发送
A-生产者
/**
* 发送事务消息
*/
public SendResult sendTransMsg(String msgBody){
//封装消息
Message<String> message = MessageBuilder.withPayload(msgBody).build();
//发送事务消息
return rocketMQTemplate.sendMessageInTransaction(
//这里和事务监听器里面的事务组保持一致
"tx-producer-group",
//topic:tag
"queue_test_topic:trans-tags",message ,null);
}
B-事务监听器
通过 @RocketMQTransactionListener(txProducerGroup = "tx-producer-group") 注解标记,监听器需要实现RocketMQLocalTransactionListener 接口 , txProducerGroup 是事务组的名字。
@Component
@RocketMQTransactionListener(txProducerGroup = "tx-producer-group")
public class MyTransactionCheckListener implements RocketMQLocalTransactionListener {
public static final Logger LOGGER = LoggerFactory.getLogger(MyTransactionCheckListener.class);
Random random = new Random();
@Override
public RocketMQLocalTransactionState executeLocalTransaction(org.springframework.messaging.Message msg, Object arg) {
//执行业务,保存本地事务
//保存成功
if(random.nextInt() % 2 == 0){
LOGGER.info("本地事务提交成功...");
return RocketMQLocalTransactionState.COMMIT;
}
LOGGER.info("本地事务提交未知...");
return RocketMQLocalTransactionState.UNKNOWN;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(org.springframework.messaging.Message msg) {
//这里查询本地事务状态
if(random.nextInt() % 2 == 0){
LOGGER.info("本地事务回查...COMMIT");
return RocketMQLocalTransactionState.COMMIT;
}
LOGGER.info("本地事务回查...ROLLBACK");
return RocketMQLocalTransactionState.ROLLBACK;
}
}
C-消费者
@Slf4j
@Component
@RocketMQMessageListener(topic = "queue_test_topic",selectorExpression="*",consumerGroup = "queue_group_test")
public class RocketMQMsgListener implements RocketMQListener<MessageExt> {
@Override
public void onMessage(MessageExt message) {
byte[] body = message.getBody();
String msg = new String(body, CharsetUtil.UTF_8);
log.info("接收到消息:{}", msg);
}
}
D-测试
@RequestMapping("/sendTrans")@ResponseBodypublic SendResult sendTrans(String msg) { //formats: `topicName:tags` return rocketMQProducer.sendTransMsg(msg);}
RocketMQ的主要使用的场景
A-做延迟消息 比如订单超时的查询即取消
B-交易、充值、流计算、消息推送、日志流式处理、binglog分发
C-在高并发和高吞吐量的条件下
D-需要进行解耦或者消峰
E-大数据量的处理操作
欢迎进行学习交流,不足之处请指出,喜欢麻烦点赞+收藏,谢谢各位大佬了