作者:XsiaoHan | 来源:互联网 | 2023-08-16 12:00
提早工作利用宽泛,提早工作典型利用场景有订单超时主动勾销;领取回调重试。其中订单超时勾销具备幂等性属性,无需思考反复生产问题;领取回调重试须要思考反复生产问题。
一、序言
提早工作利用宽泛,提早工作典型利用场景有订单超时主动勾销
;领取回调重试
。其中订单超时勾销具备幂等性属性,无需思考反复生产问题;领取回调重试须要思考反复生产问题。
提早工作具备如下特点:在将来的某个工夫点执行;个别仅执行一次。
1、实现原理
生产者将带有提早信息的音讯发送到RabbitMQ交换机中,期待延迟时间完结方将音讯转发到绑定的队列中,消费者通过监听队列生产音讯。提早工作的要害在音讯在交换机中停留。
不言而喻,基于RabbitMQ实现提早工作对服务器的可靠性要求极高,交换机内部消息无长久化机制,比方单机模式服务重启,未开始的提早工作均失落。
2、组件选型
二、方案设计
(一)服务器
RabbitMQ服务须要装置x-delayed-message
插件以解决提早音讯。
(二)生产者
提早工作的实现对生产者的要求是将音讯牢靠的投递到交换机,因而应用confirm确认
机制即可。
订单生成之后,先入库,而后以订单ID为key将订单详情存入Redis中(长久化),向RabbitMQ发送异步confirm确定申请。如果收到失常投递返回,则删除Redis中订单ID为key的数据,回收内存,否则以订单ID为key,从Redis中查问出订单数据,从新发送。
(三)消费者
提早工作的实现对消费者的要求是以信息不失落的形式生产音讯,具体表现在:手动确认音讯的生产,避免音讯失落;生产端继续稳固,避免音讯沉积;音讯生产失败有重试机制。
思考到订单提早勾销属于幂等性操作,因而无需思考音讯的反复生产问题。
三、SpringBoot实现
实现局部仅贴一部分外围源码,残缺我的项目请拜访GitHub。
(一)生产者
思考到下单是极为重要的操作,因而首先将订单落库、存盘,而后进行后续操作。
for (long i = 1; i <= 10; i++) {
/* 1.模仿生成订单 */
BuOrder order = createOrder(i);
/* 2.订单入库 */
orderService.removeById(order);
orderService.saveOrUpdate(order);
/* 3.将订单存入信息Redis */
RedisUtils.setObject(RabbitTemplateConfig.ORDER_PREFIX + i, order);
/* 4.向RabbitMQ异步投递音讯 */
rabbitTemplate.convertAndSend(RabbitmqConfig.DELAY_EXCHANGE_NAME, RabbitmqConfig.DELAY_KEY, order, RabbitUtils.setDelay(30000), RabbitUtils.correlationData(order.getOrderId()));
}
生产者牢靠投递音讯
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (correlatiOnData== null) {
return;
}
String key = ORDER_PREFIX + correlationData.getId();
if (ack) {
/* 如果音讯投递胜利,则删除Redis中订单数据,回收内存 */
RedisUtils.deleteObject(key);
} else {
/* 从Redis中读取订单数据,从新投递 */
BuOrder order = RedisUtils.getObject(key, BuOrder.class);
/* 从新投递音讯 */
rabbitTemplate.convertAndSend(RabbitmqConfig.DELAY_EXCHANGE_NAME, RabbitmqConfig.DELAY_KEY, order, RabbitUtils.setDelay(30000), RabbitUtils.correlationData(order.getOrderId()));
}
}
(二)消费者
消费者端手动确认,防止音讯失落;失败主动重试。
@RabbitListener(queues = RabbitmqConfig.DELAY_QUEUE_NAME)
public void consumeNode01(Channel channel, Message message, BuOrder order) throws IOException {
if (Objects.equals(0, order.getOrderStatus())) {
/* 批改订单状态,设置为敞开状态 */
orderService.updateById(new BuOrder(order.getOrderId(), -1));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
log.info(String.format("消费者节点01生产编号为【%s】的音讯", order.getOrderId()));
}
}
消费者牢靠生产应至多开启两个及以上利用,确保音讯队列中不积压音讯。
(三)通用工具包
上述代码波及一个工具类RabbitUtils
,存在于如下依赖中,次要封装RabbitMQ极罕用的工具办法。
xin.altitude.cms
ucode-cms-common
1.4.3.1
喜爱本文点个♥️赞♥️反对一下,如有须要,可通过微信dream4s
与我分割。相干源码在GitHub,视频解说在B站,本文珍藏在博客天地。