RocketMQ
常见问题
重复消费(消费消息的幂等性)
- Producer 在发送消息时,默认会生成消息编号( msgId )
- Broker 在存储消息时,会生成结合 offset 的消息编号( offsetMsgId )
- Consumer 在消费消息失败后,将该消息发回 Broker 后,会产生新的 offsetMsgId 编号,但是 msgId 不变
消息丢失
-
消费端弄丢了数据?
- 对于消费端,如果我们在使用 Push 模式的情况下,只有我们消费返回成功,才会异步定期更新消费进度到 Broker 上。
如果消费端异常崩溃,可能导致消费进度未更新到 Broker 上,那么无非是 Consumer 可能重复拉取到已经消费过的消息。关于这个,就需要消费端做好消费的幂等性
- 对于消费端,如果我们在使用 Push 模式的情况下,只有我们消费返回成功,才会异步定期更新消费进度到 Broker 上。
-
生产者
- 可以设置三次发送消息重试
-
Broker进行持久化
- 刷盘方式:同步刷盘、异步刷盘
- 复制方式:同步复制、异步复制
消费者获取消息有几种模式
- PushConsumer(推送模式)
- PullConsumer(拉取模式)
顺序消息扩容的过程中,如何在不停写的情况下保证消息顺序
- 成倍扩容,实现扩容前后,同样的 key,hash 到原队列,或者 hash 到新扩容的队列
- 扩容前,记录旧队列中的最大位点。
- 对于每个 Consumer Group ,保证旧队列中的数据消费完,再消费新队列,也即:先对新队列进行禁读即可。
使用案例
消息里面指定Topic
发送指定Topic
消费的时候监听注解指定Topic
特性
能够保证严格的消息顺序
提供丰富的消息拉取模式
高效的订阅者水平扩展能力
实时的消息订阅机制
亿级消息堆积能力
整体架构
生产者(Producer)
- 负责产生消息,生产者向消息服务器发送由业务应用程序系统生成的消息
消费者(Consumer)
- 负责消费消息,消费者从消息服务器拉取信息并将其输入用户应用程序
消息服务器(Broker)
- 是消息存储中心,主要作用是接收来自 Producer 的消息并存储, Consumer 从这里取得消息
名称服务器(NameServer)
- 用来保存 Broker 相关 Topic 等元信息并给 Producer ,提供 Consumer 查找 Broker 信息
流程
启动 Namesrv
- Namesrv起 来后监听端口,等待 Broker、Producer、Consumer 连上来,相当于一个路由控制中心。
Broker 启动
- 跟所有的 Namesrv 保持长连接,定时发送心跳包。
Producer 发送消息
- 启动时,先跟 Namesrv 集群中的其中一台建立长连接,并从Namesrv 中获取当前发送的 Topic 存在哪些 Broker 上,然后跟对应的 Broker 建立长连接,直接向 Broker 发消息
Consumer 消费消息
- Consumer 跟 Producer 类似。跟其中一台 Namesrv 建立长连接,获取当前订阅 Topic 存在哪些 Broker 上,然后直接跟 Broker 建立连接通道,开始消费消息
Producer 三种发送消息的方式
#syncSend同步发送
- producerl向broker发送消息,执行APl时同步等待,直到broker服务器返回发送结果。
#asyncSend异步发送
- producerl向broker发送消息时指定消息发送成功及发送异常的回调方法,调用API后立即返回,producer发送消息线程不阻塞,消息发送成功或失败的回调任务在一个新的线程中执行。
#sendOneWay
- producerl向broker发送消息,执行API时直接返回,不等待broker服务器的结果。
Producer发送消息类型
顺序消息
- 调用了对应的 Orderly(syncSendOrderly,asyncSendOrderly,sendOneWayOrderly) 方法,从而实现发送顺序消息。
同时,需要传入方法参数 hashKey ,作为选择消息队列的键
RocketMQTemplate 在发送顺序消息时,默认采用 SelectMessageQueueByHash 策略(有好几种)。如此,相同的 hashKey 的消息,就可以发送到相同的 Topic 的对应队列中。
定时消息
- 指消息发到 Broker 后,不能立刻被 Consumer 消费,要到特定的时间点或者等待特定的时间后才能被消费。
- 暂时不支持任意的时间精度的延迟,而是固化了 18 个延迟级别
批量发送消息
- 循环加入集合即可,Collection messages,注意大小限制和需要同一个Topic
发送事务消息
-
RocketMQTemplate#sendMessageInTransaction()发送事务消息
-
TransactionListenerImpl 实现RocketMQLocalTransactionListener接口
-
执行本地事务
-
回查消息2种
- 通过 msg 消息,获得某个业务上的标识或者编号,然后去数据库中查询业务记录,从而判断该事务消息的状态是提交还是回滚。
- 记录 msg 的事务编号,与事务状态到数据库中(推荐)
-
Consumer消费消息类型
顺序消费
-
普通顺序消息
-
Producer 将相关联的消息发送到相同的消息队列
- 设置consumeMode = ConsumeMode.ORDERL
-
-
完全严格顺序
- 在【普通顺序消息】的基础上,Consumer 严格顺序消费
集群消费
- 配置相同的Topic,不同的消费组即可
- 只能被一个消费者消费
广播消费
- 主要是 @RocketMQMessageListener 注解通过设置了 messageModel = MessageModel.BROADCASTING ,表示使用广播消费。
- 可以被消费者组所有消费者消费
消费重试
默认情况下,达到 16 次重试次数时,Consumer 还是消费失败时,该消息就会进入到死信队列。第一次重试消费按照延迟级别为 3 开始。 所以,默认为 16 次重试消费,毕竟延迟级别最高为 18 呀,延迟级别与对应的延时时间对应
失败后
- 存储到 Topic 为 “%DLQ%” + ConsumerGroup 到死信队列,后续做相应的告警
重试次数属性在MessageExt对象里面,生产中重试一定次数失败,后应该保存到数据库,由单独的程序或者人工进行处理
消息结构
基础属性
-
topic
- 主题相当于消息的一级分类,具有相同topic的消息将发送该topic下的消息队列中,比方说一个电
商系统可以分为商品消息、订单消息、物流消息等,就可以在oroker中创建商品主题、订单主题等,所有商品的
消息发送至该主题下的消息队列中。
- 主题相当于消息的一级分类,具有相同topic的消息将发送该topic下的消息队列中,比方说一个电
-
消息体
- 即消息的内容,可以的字符串、对象等类型(可系列化)。消息的最大长度是4M。
-
消息flag
- 消息的一个标记,RocketMQ不处理,留给业务系统使用。
扩展属性
-
tag
- 相当于消息的二级分类,用于消费消息时进行过滤,可为空。
-
keys
- Message素引键,在运维中可以根据这些key快速检索到消息,可为空。
-
waitStoreMsgOK
- 消息发送时是否等消息存储完成后再返回。