# RocketMQ - 官方网站:https://rocketmq.apache.org/zh/ - 中文文档:https://rocketmq.apache.org/zh/docs/ 从网上找的工作流程图: # 普通消息的使用场景 ##### 微服务解耦 ##### 异步执行事件 ##### 数据集成 ## 生命周期 - 初始化:生产者构建并完成初始化,待发送到服务端 - 待消费:发送到服务端,对消费者可见,等待消费 - 消费中:被消费者处理,服务端会等待消费完成,如果没有收到消费者的响应,会进行重试。 - 消费提交:消费者完成消费处理,向服务端提交消费结果,服务端标记当前消息已经被处理,消费成功、失败 - 删除消息:在消息到期或存储空间不足时,将消息从物理文件中删除 发送消息时,可以设置一个key,方便查询消息轨迹。这个key最好是唯一的,比如订单编号、用户ID、Trace等。 # 延时/定时消息 **生产者设置好消息的定时时间,服务端按时投递给消费者**。一个典型的场景:用户在业务系统中发起支付,创建一笔支付单后,5分钟未付款关闭支付单。 ## 注意事项 - 定时的时间是一个毫秒级 Unix 时间戳 - 必须设置在24小时范围内,超过范围不生效 - 若设置在当前时间之前,服务端将立即投递 ## 生命周期 相比普通消息,在初始化和待消费之间,加了一个定时中的状态。服务端将延时消息单独存储,到时间以后再挪到普通消息的存储位置,暴露给消费者进行消费。 ⚠️如果大量的延时消息在同一时刻触发,会造成系统压力过大、消息延迟,影响定时精度,尽量打散定时时间。 # 顺序消息 典型的应用场景:有序的事件处理、数据实时增量同步,比如用canal同步mysql的binlog至ES或其他存储介质。 ##### 注事事项 顺序消息的关系是通过 Message Group 识别的,生产者发送顺序消息时,需要为每条顺序消息设置 Message Group,相同 Message Group 的消息遵循 FIFO 原则。 - 必须由同一个生产者投递,且投递到同一个 Message Group 才能保障顺序性 - 必须串行发送,多线程得保证顺序投递消息,建议用最简单的方式单线程串行发送 ##### 存储逻辑 相同的消息组按照先后顺序存储到同一个队列,不同消息组的消息可以混在同一个队列,但是不一定连续。 # 事务消息 分布式和微服务应用中,分布式事务是一个非常重要的组件,传统的XA事务方案资源锁定范围大、并发度低。基于普通消息很难保障一致性,因为普通消息没有协调提交、回滚的能力。而事务消息就是补充了:普通消息的二阶段提交、与本地事务绑定的能力,实现最终一致性。 - 生产者发送消息到服务端 - 服务端将消息持久化,向生产者返回Ack,确认消息发送成功 - 此时消息被标记为"暂不能投递",这种消息叫做**半事务消息** - 生产者继续执行本地事务,然后向服务端发送事务结果:提交/回滚 - 服务端收到事务结果后 + 事务提交:把半事务消息让消费者可见,让消费者成功消费 + 事务回滚:取消投递半事务消息 + 生产者异常:如果生产者因为宕机或者重启造成不可用,或者服务端收到的事务结果是 Unknown 等异常情况 + 事务悬挂:为了避免生产者异常造成事务悬挂,服务端将会对生产者主动发起回查,第一次检查默认间隔 60 秒,支持自定义配置,最多不能超过1个小时 + 事务超时:最多4个小时后超时,超时将强制回滚 + 事务回查:生产者收到服务端的回查,要检查本地事务的执行结果,服务端根据回查结果决定要不要发消息 ## 生命周期 ## 注意事项 事务消息只保证**本地主分支事务**和**下游消息发送事务**的一致性,不能保证消息消费结果和上游事务的一致性。所以下游服务要保证自己的分支事务正确处理,并做好消费重试机制,宕机、重启这种短暂的不可用,可以直接利用服务端的重试机制。在消息提交到下游消费端处理完成之前,下游分支和上游事务之间的状态可能会不一致。因此,**事务消息仅适合接受异步执行的事务场景**。 # 消费重试 当发生以下情况,将会触发消费重试机制: - 网络异常造成连接失败或请求超时 - 生产者调用服务端失败或者超时,SDK会重新投递 - 服务端节点处于重启或下线等状态 - 服务端卡顿造成请求超时 - 服务端系统异常、流控 对于事务消息超时和异常不会进行重试,走回查的逻辑。触发重试会立即重试无时间间隔,如果是流控错误,将按照指数退避策略延迟重试,指数退避策略通过以下参数控制间隔: - INITIAL_BACKOFF:第一次失败,重试需等待多久,默认1秒 - MULTIPLIER:退避倍率,默认1.6 - JITTER:随机抖动因子,默认0.2 - MAX_BACKOFF:等待间隔上限,默认120秒 - MIN_CONNECT_TIMEOUT:最短重试间隔,默认20秒 SDK内置的重试机制并不能保证消息发送一定成功,因为生产者达到重试限制后仍然发送失败,需要自己兜底处理。由于远程调用的不确定性,如果触发消息重试,可能会产生消息重复的问题,消费者也要处理好消费重复的问题,比如幂等性消费。 # 死信队列 当一条消息达到最大重试次数仍然消费失败,服务端将挪到一个特殊的队列,这个队列中的消息无法再被消费者正常消费。SDK有开启死信队列的消费API,默认3天后自动删除。 # 流控机制 - 当消费组的消费位点处于队列的最大消费位点,而某些业务又在回溯队列的历史消息,这时就会触发流控 - 消费过慢,导致队列中大量的消息堆积,超过一定数量也会触发流控,目的是减少下游消费的压力 为避免触发消息流控,可以利用可观测性功能监控系统容量等,保证资源充足。 # 消费模式 一条消息支持被多个消费组订阅,每个消费组可以初始化若干个消费者。消费者有两种模式的消费: - 广播(Broadcast) - 共享(Share) ##### 广播消费 每个消费组只初始化唯一的一个消费者,多个消费组订阅这个 topic 时,每个消费者都能消费到。该方式一般可用于网关推送、配置推送、集群实例之间同步缓存等场景。 ##### 共享消费 每个消费组下初始化多个消费者,这些消费者共同分担消息,1条消息只被其中1个消费者处理。可以实现消费组内流量的水平拆分和负载均衡,一般用于微服务解耦。 ⚠️PushConsumer默认且仅使用消息粒度负载均衡策略,同一消费组内的多个消费者将按照消息粒度平均分摊所有消息。 # 消息存储