mq使用不当,造成生产线上环境的服务奔溃问题记录

案例描述:

线上采用canel监听A表的status状态变化,只要有变化就通过mq发送消息到对应的消费者端处理。

消费者端的程序代码这样子写(因涉及公司业务,这里只是举个大致的代码示例)

代码大致的思路就是,监听队列QUEUE_B,然后消费发送到QUEUE_B的消息,如果消费过程中发生异常,就将消息重新发回队列中去。

一开始上线这个功能是正常的,因为doSomeThing业务里面没有任何异常,消息能够被正常消费。

后来某个版本上线后,突然有一天晚上,发现线上的服务,大部分宕机,监控短信响个不停。

经核实,就是因为doSomeThing里面的代码异常了,导致mq消费失败,然后代码里又将消息重新推回队列中。这样子问题就来。

程序本身有问题,mq消费消息永远是失败的,然后又刚好设置重新归队,导致一直在刷mq消费失败的日志,结果80G的磁盘没多久就撑爆了,导致同服务器的其他服务因为磁盘写入日志的问题,全线奔溃。。。代价有点惨重。

@Component
@Slf4j
public class MsgReceiverB {
    @RabbitListener(queues = RabbitMqConfig.QUEUE_B)
    public void onMessage(Message message, Channel channel) throws Exception {
        try {
            log.info("接收处理队列MsgReceiverB当中的消息: " + new String(message.getBody()));
            //处理某业务的代码,这里以doSomeThing示例
            doSomeThing();
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        } catch (Exception e) {
            log.error("QUEUE_B消费异常={}",e.getMessage());
            channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
        }
    }

    private void doSomeThing() {
        //获取用户登录信息,原先获取不到用户信息是返回null,后来获取不到直接抛错,导致了这次血案的发生
        System.out.println("处理业务");
    }
}

 

问题总结:

出现这种问题的原因:开发对应业务的同事对mq的特性不是很熟悉。虽然一开始没有问题,但是埋下了隐患。后来某同事

因需求变动,导致doSomeThing()代码抛错就成了引爆这个导火线的人,直接导致了这次线上事故的发生。

笔者认为合理的处理方式有以下几种

第一种:消息消费失败后,不要设置重新归队,因为代码没有执行手工确认这个动作,消息是不会从mq中移出的,也就是消息

不会丢失,等消费者下次再启动的时候,就会重新消费。

第二种:消息消费失败后,直接让消息进入死信队列,在死信队列里,再起消费端重新消费,如果消费几次还是失败的话,

发消息通知人工处理。(根据消息的重要性判断是否需要人工处理,还是直接丢弃)

第三种:消息消费失败,直接持久化到数据库,nosql数据库或者sql数据库都可以,然后再发消息人工介入处理。(根据消息的重要性判断是否需要人工处理,还是直接丢弃)

以上纯属笔者个人意见,如有更好的方案,欢迎下方评论。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值