- 作者:老汪软件技巧
- 发表时间:2024-12-01 17:03
- 浏览量:
引言
小宾在RocketMQ系列的上一篇文章中,和大家一起初识了RocketMQ;今天将继续学习RocketMQ支持的四种消息类型,其中事务消息和顺序消息是小宾认为RocketMQ之所以能够后来居上的重要因素,其中不乏很多精妙的设计思想
今天小宾将和大家继续深入RocketMQ,了解其能够在众多MQ产品中脱颖而出的原因,感兴趣的同学可以持续关注我的专栏:MQ中间件
四大消息类型
RocketMQ支持的消息类型有四种:普通消息、顺序消息、定时/延时消息和事务消息,其中定时消息和延时消息其本质实现是完全一致的,因此我们就归纳到一种类型进行学习
普通消息
普通消息是最基础的消息类型,是所有MQ中间件都支持的消息类型,其主要的生命周期就是生产者封装数据成消息,发送到服务端持久化存储,由消费者获取消息处理解析其内部数据
其常见的使用场景就是我们熟知的异步、解耦、削峰填谷,对于消息的传递顺序和一致性没有特别要求
注意: 5.0版本过后的RocketMQ中,一个Topic只支持一种类型的消息,因此普通消息(Normal)只能发送到配置消息类型为Normal的Topic中,否则会生产失败
在实际的业务场景中,通常会给每个消息设置一个唯一键Message Key,例如订单ID、用户ID或者链路traceID等,用于异常问题的排查定位
定时/延时消息
适用于定时调度触发、任务超时等场景,例如淘宝购物点击结算后暂不付款,此时该订单会保留一段时间等待用户完成付款操作,若超时后付款订单取消;该场景就是基于定时/延时消息实现的,发起结算时生产一个延时消息,超时后消息对消费者(订单业务系统)可见,消费端处理消息取消该订单
其实现原理是,为消息设置一个时间戳,无论是定时还是延时消息,都是时间戳而非延时时长;该消息发送到服务端后不会马上流转为可消费状态,而是要在定时时间戳之后才对消费者可见。定时时间戳的单位是毫秒级,但RocketMQ提供的精度是1000ms,也就是秒级别的精度
注意:延时时长不能设置超过24小时,否则消息会同普通消息一样立马被投递,不会延迟 (这点小宾有点疑惑, 阿里为啥不在生产时就校验延时时长,显式的抛出错误,而是隐式的降级处理;猜测可能是不想在服务端做时长校验,会有时钟精度问题,hh);定时时间也不能设置在当前时间之前,否则服务端也会立即投递消息
同样,定时/延时消息只能被发送到配置为Delay消息类型的Topic中,否则生产会失败;异常情况下,服务端异常宕机后从磁盘持久化数据中恢复,可能会导致定时消息在预期时间之后投递,这取决于恢复时间在定时时间之前还是之后
避免设置大量定时时间相同的消息,会导致同时刻大量的消息需要被投递,对服务端造成较大压力
顺序消息
适用于对消息传递有顺序要求的场景,例如转账、库存管理等业务系统;消费者按照消息的生产顺序依次获取消息,从而实现业务场景下的顺序处理
RocketMQ中顺序消息需要绑定到消息组Message Group中管理,通常一个场景下的顺序消息对应一个消息组,消息在消息组维度保持有序;同一个消息组内的消息遵从FIFO,而不同消息组之间则没有顺序关系
消息的整体顺序性需要两个方面的保证,一个是生产顺序性,一个是消费顺序性
生产顺序性
同一个消息组的消息在服务端必须存储在同一个队列中,且存储保持串行发送的顺序;不同消息组的消息可以共用队列,不同消息组之间的消息没有顺序关系
消费顺序性
顺序消息只能发送到配置消息类型为FIFO的Topic中,否则会生产失败
注意: 避免批量消费顺序消息,若批量消费出现部分失败,批量消息被重试消费,可能导致已成功处理的消息被多次处理;若强需批量消费,建议消费端做好消费幂等校验;避免将大量消息划分到同一消息组,否则会存储在同一队列中,导致单队列热点问题
事务消息
适用于要求多个业务操作需要保障事务(ACID)特性的场景,还是以淘宝电商的场景为例,订单支付、物流、会员、库存多个业务系统的变更操作;如在订单支付成功后,物流需要新增商品物流信息、会员需要更新用户积分、库存需要更新商品数量;订单支付的变更结果需要和下游中的各个系统的变更结果保持一致性,例如订单支付失败后,上述各下游系统的变更不该实际生效
注意:RocketMQ的事务消息只能保证最终一致性,无法保证线性一致性
RocketMQ中的事务消息基于两阶段提交机制,需要生产者基于本地事务的执行结果在第二阶段确认事务消息提交或回滚上述场景可基于RocketMQ的事务消息实现如下:
订单支付系统开启本地事务,发送事务半消息(half message)到服务端服务端响应ack到生产者,确认已收到了半事务消息(小宾理解,此举与Tcp的握手类似,主要是确认服务端状态正常)订单支付根据本地事务执行结果(支付成功/失败),选择提交或回滚半事务消息若commit半事务消息,则服务端投递消息给消费者(物流、会员、库存)若rollback半事务消息,则服务端丢弃半事务消息,不投递如果因为生产者宕机或本地事务执行时间过长,导致服务端未收到第二阶段的确认信息,或服务端收到的信息为Unknown未知状态;在配置的超时阈值之后,服务端会主动回查生产者询问其本地事务执行结果生产者收到回查请求后,检查本地事务状态,对第二阶段确认
事务消息只能发送到配置消息类型为Transaction的Topic中,否则会生产失败
事务消息配置有超时时间,若在时间内生产者未确认第二阶段提交,该事务消息会被回滚