1.安装部署
windows环境演示:
官方地址: https://rocketmq.apache.org/release_notes/release-notes-4.3.2/
配置rocketMq环境变量
启动nameserver命令: start mqnamesrv.cmd
启动broker: start mqbroker.cmd -n localhost:9876
验证是否启动成功: jsp -l
以上来看,我们nameserver以及broker都启动完成了
2.结构介绍
nameserver: 一个无状态节点,用于部署集群,每个集群没有任何信息同步
broker: broker分为master和slaver节点,每个broker与nameserver集群中的所有节点建立长连接,定时(30s)注册Topic信息到NameServer; NameServer定时(10s)扫描所有存活的Broker的连接,如果2分钟没有心跳,自动断开
Producer: Producer与NameServer中任意一个节点建立长连接,定期从NameServer中拉取Topic路由的信息,并且提供Topic服务的Master(Broker)建立长连接,定时向Master发送心跳
Producer定时(30s)从NameServer中获取所有的Topic队列
Produce每隔30s,向所有关联的broker发送心跳
broker每隔10s扫描存活的连接,如果2分钟没有收到心跳数据,自动与producer断开连接
Consumer: Producer与NameServer中任意一个节点建立长连接,定期从NameServer中拉取Topic路由的信息,并且提供Topic服务的Master丶slaver(Broker)建立长连接,定时向Master丶slaver发送心跳
Consumer既可以从master订阅消息,也可以从slaver订阅消息,取决于broker的配置
Consumer定时(30s)从NameServer中获取所有的Topic队列
Consumer每隔30s,向所有关联的broker发送心跳
代码实现:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.4.3</version> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> </dependencies>
配置文件:
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: topic-default-group
Producer:
@Controller
public class DemoController {
@Resource
private RocketMQTemplate rocketMQTemplate;
@RequestMapping("/consumer")
@ResponseBody
private String consumer(){
Map map = new HashMap();
map.put("id",2);
map.put("name","ff0");
rocketMQTemplate.convertAndSend("topicA",map);
return "OK";
}
}
发送成功
Consumer:
@Component
@RocketMQMessageListener(consumerGroup = "topic-default-group", topic = "topicA")
public class DemoConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println(s);
}
}
成功消费
3.特性/优势
3.1顺序消费
例如:我们需要保证 订单创建 --> 订单支付 --> 订单完成 --> 订单推送,整个流程的局部一致性
消息发送Producer:
@RequestMapping("/consumerOrder")
@ResponseBody
private String consumerOrder() throws InterruptedException {
rocketMQTemplate.syncSendOrderly("topicA","订单创建","order = 1");
rocketMQTemplate.syncSendOrderly("topicA","订单支付","order = 1");
rocketMQTemplate.syncSendOrderly("topicA","订单完成","order = 1");
rocketMQTemplate.syncSendOrderly("topicA","订单推送","order = 1");
return "OK";
}
主要是通过第三个参数 order = 1,会根据它的hash值计算,放到对应的哪个队列,从而保证局部的消息都在一个队列
Consumer:
3.2事务型消息
1.producer发送事务消息(prepared消息)
@RequestMapping("/transaction")
@ResponseBody
private String transaction() {
Message<String> message = MessageBuilder.withPayload("锁定库存").build();
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("topicStock", message, null);
System.out.println("发送状态:" + result.getLocalTransactionState());
return "success";
}
2.执行本地事务
@Component
@RocketMQTransactionListener
@Slf4j
public class TransactionStockListener implements RocketMQLocalTransactionListener {
private ConcurrentHashMap<String, Object> localTrans = new ConcurrentHashMap<>();
/**
* 发送prepare消息成功,用于执行本地事务
* @param message 消息
* @param o
* @return 返回事务状态
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
try {
log.info("【本地业务执行完毕】 msg:{}, Object:{}", message, o);
// 用于记录消息事务,一般创建日志表来记录
localTrans.put(message.getHeaders().getId()+"", message.getPayload());
// 执行本地事务,创建订单
System.out.println("订单创建完毕");
// 提交事务
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
e.printStackTrace();
log.error("【执行本地业务异常】 exception message:{}", e.getMessage());
// 回滚事务
return RocketMQLocalTransactionState.ROLLBACK;
}
}
/**
*
* @param message 通过transactionId判断该消息的事务状态
* @return
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
log.info("【执行检查任务】");
return RocketMQLocalTransactionState.UNKNOWN;
}
}
主要是为了保证消息事务与本地事务一致性
localTrans为了记录本地事务日志,一般用于日志表记录做补偿操作
补偿机制: 定时任务扫描发送待发送的消息,重新发送消息
3.消费消息
这一步主要是为了关注Commit状态的消息,被消费端成功消费,Rollback状态的消息,无法消费
@Component
@RocketMQMessageListener(consumerGroup = "topic-default-group", topic = "topicStock")
public class StockConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
// 库存扣减消息
System.out.println(s);
}
}
4.消息存储
RocketMQ消息主要是通过 CommitLog和ConsumerQueue来完成
CommitLog: 用于存储消息的物理文件
ConsumerQueue: 用户记录msg在Commit Log的offset以及消息的大小和tag