Rabbtimq实战应用

背景

在前端时间开发的项目中,在消息通知模块业务上有钉钉、微信、短信、邮箱、站内消息通知,一个接口下可能会同时调用这5个消息通知方式,如果是同步的方式来进行处理,接口的效应速率会大大降低,而且5个消息的发送不统一处理代码的耦合性太高,根据这两点我们决定采用消息中间件Rabbitmq来进行处理消息的发送。

好处:
1、消息定制统一的消息模板发送消息时将消息封装到消息模板统一处理是代码更加便于维护和清晰
2、发送消息时只需要将消息投递到消息队列,将同步变异步使得接口的响应速率更快

坏处:
使用Rabbitmq可能会出现消息的丢失、消息重复消费等问题需要解决


方案流程图

在这里插入图片描述


RabbitMQConfig

     消息队列、交换机、绑定关系的创建
@Configuration
public class RabbitMQConfig {

    public static final String NOTICE_QUEUE_NAME = "notice.queue";
    public static final String NOTICE_EXCHANGE_NAME = "notice.exchange";
    public static final String NOTICE_ROUTING_KEY_NAME = "notice.routing.key";

    @Bean
    public Queue noticeQueue() {
        return new Queue(NOTICE_QUEUE_NAME, true);
    }

    @Bean
    public DirectExchange noticeExchange() {
        return new DirectExchange(NOTICE_EXCHANGE_NAME, true, false);
    }

    @Bean
    public Binding noticeBinding() {
        return BindingBuilder.bind(noticeQueue()).to(noticeExchange()).with(NOTICE_ROUTING_KEY_NAME);
    }
    }

RabbitMQTemplateConfig

   消息发送到交换机监听及消息发送失败的处理
@Configuration
@Slf4j
public class RabbitMQTemplateConfig {

    @Autowired
    private IMessageLogService messageLogService;

    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter());
        //设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                log.info("消息成功发送到Exchange");
                String msgId = correlationData.getId();
                MessageLog messageLog = new MessageLog();
                messageLog.setId(Integer.valueOf(msgId));
                messageLog.setStatus(MessageLog.MsgLogStatus.DELIVER_SUCCESS);
                messageLogService.updateById(messageLog);
            } else {
                log.error("消息发送到Exchange失败, {}, cause: {}", correlationData, cause);
            }
        });

        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            log.info("消息从Exchange路由到Queue失败: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", exchange, routingKey, replyCode, replyText, message);
        });
        return rabbitTemplate;
    }

    @Bean
    public MessageConverter jackson2JsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}

RabbitMsgProducer

  消息发送
@Slf4j
@Component
public class RabbitMsgProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public boolean sendMessage(MessageParam messageParam) {
        if (Objects.nonNull(messageParam)) {
            CorrelationData correlationData = new CorrelationData(messageParam.getMsgId());
            // 发送消息
            rabbitTemplate.convertAndSend(RabbitMQConfig.NOTICE_EXCHANGE_NAME, RabbitMQConfig.NOTICE_ROUTING_KEY_NAME,
                    MessageHelper.objToMsg(messageParam), correlationData);
        }
        return true;
    }
    }

RabbitMsgConsumer

   消息消费
@Component
@Slf4j
public class RabbitMsgConsumer {

    @RabbitListener(queues = {RabbitMQConfig.NOTICE_QUEUE_NAME})
    public void generalConsume(Message message, Channel channel) throws IOException, InterruptedException {
   //1、根据message MessageHelper.msgToObj(message, MessageParam.class);获取消息信息
   //2、获取消息ID去消息日志里判断消息是否被消费
   //3、消息消费
   //4、消费成功手动ACK,消费失败Nack,对应修改日志状态
}
}

主要解决的问题

1、利用Rabbitmq解决了代码的耦合,接口响应速率较慢的问题
2、利用消息日志记录消息状态 解决消息的重复消费及消息丢失的问题
3、利用Rabbitmq的confirm机制(消息发送到交换机可能出现消息丢失)及手动ACK解决消息丢失问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值