rocketmq学习
1. RocketMQ 是什么?
RocketMQ 是一个消息队列中间件。
它的核心作用是:
让一个系统把消息发出去,另一个系统异步接收并处理。
比如:
订单系统 ---> RocketMQ ---> 库存系统 订单系统 ---> RocketMQ ---> 积分系统 订单系统 ---> RocketMQ ---> 短信系统订单系统只负责说:
“用户下单了。”
然后把这条消息发到 RocketMQ。
库存系统看到这个消息,就扣库存。
积分系统看到这个消息,就加积分。
短信系统看到这个消息,就发短信。
这样订单系统就不需要自己一个个调用它们。
2. 为什么要用 RocketMQ?
主要解决这几个问题。
1)异步处理,提高速度
不用消息队列时:
下单 -> 扣库存 -> 加积分 -> 发短信 -> 返回成功用户要等所有步骤完成。
用了 RocketMQ:
下单 -> 发送消息 -> 返回成功扣库存、加积分、发短信后面慢慢处理。
这样接口响应更快。
2)系统解耦
不用 MQ 时,订单系统可能要直接调用库存系统、短信系统、积分系统。
订单系统强依赖库存系统 订单系统强依赖短信系统 订单系统强依赖积分系统如果短信系统挂了,订单系统可能也受影响。
用了 MQ:
订单系统只管发消息 其他系统自己订阅消息订单系统不用关心谁来处理。
3)削峰填谷
比如秒杀场景,一瞬间来了 10 万个请求。
如果这些请求直接打到数据库,数据库可能崩。
可以先把请求写入 MQ:
大量请求 -> RocketMQ -> 后台慢慢消费 -> 数据库RocketMQ 相当于一个缓冲池。
3. RocketMQ 里的核心概念
你先记住这些:
Producer:生产者,发消息的人 Consumer:消费者,收消息的人 Topic:消息主题,消息分类 Group:组,表示一类生产者或消费者 Broker:消息服务器,真正存消息的地方 NameServer:注册中心,帮客户端找到 Broker Message:消息本身 Tag:Topic 下面的二级分类 Queue:Topic 内部的队列分片下面一个个讲。
4. Topic 是什么?
Topic 是消息的分类。
比如你有这些业务:
订单消息 支付消息 优惠券消息 库存消息你可以设计成:
order_topic pay_topic coupon_topic stock_topicTopic 就像一个“频道”。
生产者发送消息时,要指定发到哪个 Topic。
消费者订阅消息时,也要指定监听哪个 Topic。
例如:
订单系统发送消息到 order_topic 库存系统监听 order_topic 积分系统监听 order_topic 短信系统监听 order_topic只要有系统对订单消息感兴趣,就订阅order_topic。
Topic 的简单理解
你可以这样记:
Topic = 消息属于哪一类比如:
下单成功消息 -> order_topic 支付成功消息 -> pay_topic 优惠券过期消息 -> coupon_topic5. Group 是什么?
Group 分两种:
Producer Group Consumer Group但实际开发里,你最需要理解的是Consumer Group。
5.1 Producer Group 是什么?
Producer Group 是生产者组。
它表示一类发送消息的生产者。
比如订单服务有多个实例:
order-service-1 order-service-2 order-service-3它们都负责发送订单消息,可以属于同一个 Producer Group:
order_producer_group小白阶段不用太纠结 Producer Group,它更多是标识生产者身份。
5.2 Consumer Group 是什么?
Consumer Group 是消费者组。
它非常重要。
它表示:
一组消费者共同消费同一类消息。
比如库存服务部署了 3 台机器:
stock-service-1 stock-service-2 stock-service-3它们都属于:
stock_consumer_group那么一条消息只会被这个组里的其中一个实例消费。
也就是说:
order_topic 有一条消息:用户A下单了 stock-service-1 消费 stock-service-2 不消费 stock-service-3 不消费这样可以分摊压力。
6. 一个 Topic 可以被多个 Group 消费吗?
可以,而且这是 RocketMQ 很重要的地方。
假设订单系统发了一条消息:
Topic: order_topic 消息内容: 用户A下单成功现在有三个系统都想处理这条消息:
库存系统:扣库存 积分系统:加积分 短信系统:发短信它们应该用不同的 Consumer Group:
stock_consumer_group point_consumer_group sms_consumer_group这样这条消息会被每个 Group 都消费一次。
也就是:
stock_consumer_group 消费一次 point_consumer_group 消费一次 sms_consumer_group 消费一次但是在同一个 Group 内部,只会有一个消费者实例消费这条消息。
7. Topic 和 Group 的关系
这是最容易混乱的地方。
你可以这样理解:
Topic:消息分类 Group:谁来消费这一类消息举个例子:
Topic: order_topic Consumer Group: - stock_group:库存系统消费 - sms_group:短信系统消费 - point_group:积分系统消费关系图:
订单系统 | | 发送订单消息 v order_topic | |---- stock_group -> 扣库存 | |---- sms_group -> 发短信 | |---- point_group -> 加积分所以:
同一个 Topic 可以被多个 Group 订阅。 不同 Group 都能拿到同一份消息。 同一个 Group 内部多个消费者是竞争消费。8. Consumer Group 最重要的规则
假设:
Topic = order_topic Consumer Group = stock_group如果你启动了 3 个库存服务实例:
stock-service-1 stock-service-2 stock-service-3它们都用同一个stock_group。
那么消息会被负载均衡:
消息1 -> stock-service-1 消息2 -> stock-service-2 消息3 -> stock-service-3 消息4 -> stock-service-1这叫集群消费。
默认常用的就是这种。
如果你想让每个实例都收到同一条消息,那叫广播消费。
比如:
消息1 -> stock-service-1 消息1 -> stock-service-2 消息1 -> stock-service-3但业务开发中更常用的是集群消费。
9. Tag 是什么?
Tag 是 Topic 下面更细的分类。
比如你有一个 Topic:
order_topic但是订单消息里面又分:
下单成功 订单取消 订单超时 订单完成可以用 Tag:
order_topic: create order_topic: cancel order_topic: timeout order_topic: finish消费者可以只订阅自己关心的 Tag。
比如库存系统只关心:
order_topic 下的 create 和 cancel短信系统只关心:
order_topic 下的 create简单记:
Topic = 大分类 Tag = 小分类10. Message 是什么?
Message 就是消息本身。
一般包括:
Topic Tag Key Body例如:
{"topic":"order_topic","tag":"create","key":"order_10001","body":{"orderId":10001,"userId":20001,"amount":99.9}}其中:
Topic:发到哪个主题 Tag:消息小分类 Key:消息唯一标识,方便排查 Body:真正的业务数据11. Broker 是什么?
Broker 是 RocketMQ 里真正存消息的服务器。
生产者发送消息,实际上是发给 Broker。
消费者消费消息,也是从 Broker 拉消息。
Producer -> Broker -> Consumer如果说 RocketMQ 是快递系统,那么 Broker 就是快递仓库。
12. NameServer 是什么?
NameServer 类似注册中心。
它的作用是:
告诉 Producer 和 Consumer,Broker 在哪里。
因为生产者和消费者并不知道 Broker 地址,所以它们先连接 NameServer。
Producer -> NameServer:请问 order_topic 在哪个 Broker? NameServer -> Producer:在 Broker-A Producer -> Broker-A:发送消息你可以把 NameServer 理解成“地址簿”。
13. Queue 是什么?
一个 Topic 内部会分成多个 Queue。
比如:
order_topic - queue0 - queue1 - queue2 - queue3为什么要分多个 Queue?
为了提高并发能力。
如果只有一个队列,一个消费者慢慢消费,速度有限。
多个 Queue 可以让多个消费者并行消费。
queue0 -> consumer1 queue1 -> consumer2 queue2 -> consumer3 queue3 -> consumer4小白阶段你不用主动操作 Queue,知道 Topic 内部有多个队列就行。
14. RocketMQ 的整体结构
完整流程大概是:
NameServer:负责发现 Broker Broker:负责存消息 Producer:发送消息 Consumer:消费消息 Topic:消息分类 Group:生产者/消费者分组整体图:
NameServer ^ | 查询 Broker 地址 | Producer -----> Broker -----> Consumer | | | 发送消息 存消息 拉取消息 | Topic + Tag + Body15. 开发中怎么设计 Topic 和 Group?
假设你做一个优惠券系统。
业务有:
优惠券创建 优惠券领取 优惠券使用 优惠券过期可以设计 Topic:
coupon_topic然后用不同 Tag:
create receive use expire比如优惠券过期消息:
Topic: coupon_topic Tag: expire Body: {"couponId": 1001}消费者:
coupon_expire_consumer_group它监听:
coupon_topic:expire到时间后消费消息,把优惠券状态改成已过期。
16. RocketMQ 如何引入?以 Spring Boot 为例
常见方式是引入 RocketMQ Spring Boot Starter。
Maven 依赖一般类似这样:
<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.3.0</version></dependency>版本要根据你的 Spring Boot 和 RocketMQ 服务端版本调整。
17. 配置 application.yml
比如:
rocketmq:name-server:127.0.0.1:9876producer:group:order_producer_group这里:
name-server:NameServer 地址 producer.group:生产者组名18. 生产者怎么发消息?
在 Spring Boot 里,可以用RocketMQTemplate。
@RestController@RequestMapping("/order")publicclassOrderController{privatefinalRocketMQTemplaterocketMQTemplate;publicOrderController(RocketMQTemplaterocketMQTemplate){this.rocketMQTemplate=rocketMQTemplate;}@PostMapping("/create")publicStringcreateOrder(){// 1. 模拟订单创建成功StringorderId="10001";// 2. 发送订单创建消息rocketMQTemplate.convertAndSend("order_topic:create","订单创建成功,订单ID:"+orderId);return"下单成功";}}这里:
"order_topic:create"表示:
Topic = order_topic Tag = create19. 消费者怎么接收消息?
写一个监听器:
@Component@RocketMQMessageListener(topic="order_topic",consumerGroup="stock_consumer_group",selectorExpression="create")publicclassStockConsumerimplementsRocketMQListener<String>{@OverridepublicvoidonMessage(Stringmessage){System.out.println("库存系统收到订单消息:"+message);// 这里可以写扣库存逻辑}}解释一下:
topic="order_topic"表示监听订单主题。
consumerGroup="stock_consumer_group"表示这个消费者属于库存消费者组。
selectorExpression="create"表示只消费 Tag 为create的消息。
20. 一个完整小例子
订单系统发消息
rocketMQTemplate.convertAndSend("order_topic:create","用户下单成功,订单ID:10001");库存系统消费消息
@RocketMQMessageListener(topic="order_topic",consumerGroup="stock_consumer_group",selectorExpression="create")publicclassStockConsumerimplementsRocketMQListener<String>{@OverridepublicvoidonMessage(Stringmessage){System.out.println("扣库存:"+message);}}短信系统消费消息
@RocketMQMessageListener(topic="order_topic",consumerGroup="sms_consumer_group",selectorExpression="create")publicclassSmsConsumerimplementsRocketMQListener<String>{@OverridepublicvoidonMessage(Stringmessage){System.out.println("发短信:"+message);}}注意,这两个消费者用了不同的 Consumer Group:
stock_consumer_group sms_consumer_group所以同一条订单消息,库存系统和短信系统都能收到。
21. 如果两个消费者用了同一个 Group 会怎样?
比如:
consumerGroup="order_consumer_group"两个消费者都用这个组。
那么同一条消息只会被其中一个消费者收到。
消息1 -> 消费者A 消息2 -> 消费者B 消息3 -> 消费者A这叫负载均衡。
所以千万记住:
不同业务系统,要用不同 Consumer Group。 同一个业务系统的多个实例,用同一个 Consumer Group。这是面试和实战都很重要的一句话。
22. RocketMQ 有哪些常见消息类型?
1)普通消息
最常用。
订单创建后,发送一条订单消息2)延迟消息
消息不是立刻消费,而是过一段时间再消费。
比如优惠券过期:
优惠券 20 小时后过期可以发送延迟消息:
20 小时后消费者才收到消息然后消费者把优惠券状态改为过期。
这就是你之前说的优惠券过期方案里可能会用到的方式。
3)顺序消息
保证消息按顺序消费。
比如订单状态变化:
创建订单 -> 支付订单 -> 发货 -> 完成这些消息最好按照顺序消费。
4)事务消息
解决“本地事务”和“发消息”一致性问题。
比如:
订单创建成功后,必须发消息通知库存系统如果订单创建成功了,但消息发送失败,就会出问题。
事务消息就是用来保证这类场景的一致性。
23. RocketMQ 使用中的几个重要问题
1)消息会不会重复消费?
会。
RocketMQ 不能保证业务层面绝对只消费一次。
所以消费者代码要做幂等。
幂等是什么意思?
就是同一条消息消费多次,结果也一样。
比如扣库存时,不能简单写:
库存 = 库存 - 1否则重复消费就会多扣。
应该记录这条订单是否已经扣过库存:
如果订单10001已经扣过库存,就不要重复扣2)消息消费失败怎么办?
如果消费者抛异常,RocketMQ 会重试。
比如:
@OverridepublicvoidonMessage(Stringmessage){thrownewRuntimeException("消费失败");}RocketMQ 会认为这条消息没有消费成功,后面会重新投递。
所以你的消费逻辑要注意:
成功就正常返回 失败就抛异常3)消息堆积是什么?
如果生产者发消息太快,消费者处理太慢,消息就会越积越多。
这叫消息堆积。
比如:
每秒产生 10000 条消息 每秒只能消费 1000 条消息剩下的消息就会堆积在 Broker。
解决方式:
增加消费者实例 优化消费逻辑 增加 Topic 队列数 拆分业务 Topic24. 面试怎么回答 Topic 和 Group?
你可以这样说:
Topic 是 RocketMQ 中消息的一级分类,生产者发送消息时需要指定 Topic,消费者通过订阅 Topic 来消费消息。
Group 分为 Producer Group 和 Consumer Group。实际开发中更常用的是 Consumer Group,它表示一组消费者实例。
同一个 Consumer Group 内部是竞争消费,一条消息只会被组内一个消费者消费;不同 Consumer Group 之间是独立消费,同一条消息可以被多个不同业务组分别消费。
所以一般不同业务系统使用不同 Consumer Group,同一业务系统的多个实例使用同一个 Consumer Group。
这段可以背下来。
25. 小白最容易记混的点
Topic 不是消费者
Topic 只是消息分类。
order_topic 不是订单服务 order_topic 是订单消息的分类Group 不是 Topic 的子分类
Group 表示消费者身份,不是消息分类。
Topic = 消息是什么 Group = 谁来消费Tag 才是 Topic 下面的小分类
Topic = order_topic Tag = create / cancel / pay / finish26. 你可以这样记
Producer:发消息的人 Consumer:收消息的人 Topic:消息大分类 Tag:消息小分类 Group:一组生产者或消费者 Broker:存消息的服务器 NameServer:帮你找 Broker 的地址簿 Queue:Topic 内部的并发队列 Message:真正传递的数据27. 最后用一句话串起来
比如订单创建成功:
订单服务作为 Producer, 把一条 order_topic:create 消息发送到 Broker, Broker 负责保存消息, 库存服务、短信服务、积分服务作为不同 Consumer Group, 分别订阅 order_topic, 收到消息后执行扣库存、发短信、加积分等逻辑。 NameServer 负责告诉生产者和消费者 Broker 在哪里。你现在先重点记这三个关系就够了:
Topic:消息分类 Tag:Topic 下的小分类 Consumer Group:消费者分组以及这句:
同一个 Group 内部,一条消息只给一个消费者; 不同 Group 之间,同一条消息可以各消费一遍。这就是 RocketMQ 入门里最核心的东西。
