如何应对线上故障

本人将作为一个开发者的角度去思考线上故障的处理和解决方案,鉴于本人是小菜鸡,如有不对,多多请各位大佬指正!感激不尽

一、类型
线上故障类型很多,目前作者就遇到过几种
(1)线上OOM问题
(2)底层资源不足导致某些重要服务被踢出
(3)底层资源不足/网络通信/其他问题 使得底层服务DB崩溃
(4)业务依赖的组件 如MQ、Redis崩溃

二、排查流程
(1)首先是OOM问题
        OOM其实算是比较常见的线上问题了,一般来说在发生OOM的时候,紧急措施应该是要立即重启,同时外部流量需要避免再继续打入此服务(不过这个一般是基架团队和网关团队的事情)。对于我们业务团队来说,更多是迅速去拿到这个OOM的Dump文件,对Dump文件进行进一步的分析。
        一般来说我们可以利用MAT进行Dump的分析

这个会告诉你,最有可能造成这个OOM的线程可能是哪个
不过实际分析的时候,我们会去看当时是对象哪个占的大,随后有historym去看调用的线程,查看哪个线程发生了问题,追踪线程的操作,当时在干什么,找到问题线程之后,拿当时的相关信息,进行翻译转义,最后结合业务特点进行代码的修改即可

(2)业务依赖的组件 如MQ、Redis崩溃
这个按理来说不属于业务团队的问题,但是其实对于业务来说,完全由能力在代码上进行防御,从而减少对外部组建的依赖,实现故障的自动同步
举个例子:MQ集群崩溃。首先我们要思考 MQ是做什么的 显而易见
八股三件套:异步、削峰、解耦
但是仅仅是会背这三个字是不够滴(主要是你没办法从这个三个字管中窥豹)想了解请移步XXXX(还没写,过段时间再写MQ相关的)

那我们就针对这三个场景看看有没有解决方案吧
首先是共有的,既然不能完全信任MQ,那么我们代码块中一定要有try catch(当然了,主流的MQ客户端一定会有异常抛出的)

分场景,首先是同一个项目中,引入了MQ
那么MQ的作用显而易见(其实也不一定,但是大概率是削峰和异步),那么作为兜底措施完全是可以在catch层降级为同步调用,由此保证可靠性
举个例子

@Component
public class MQProducer {
    @Autowired
    private MQManager mqManager;
    private final Gson gson = new Gson();
    private final DefaultMQProducer producer;
    private final String producerGroup;
    private final String nameServer;
    private final String TOPIC;
    public MQProducer(String nameServer,String producerGroup,String topic){
        this.nameServer = nameServer;
        this.producerGroup = producerGroup;
        this.producer = new DefaultMQProducer(producerGroup);
        this.TOPIC = topic;
    }

    public void start(){
        try{
            this.producer.start();
        }catch (MQClientException e){
            throw new RuntimeException("Failed to XXXXX",e);
        }
    }

    public void shutdown(){
        this.producer.shutdown();
    }

    public void send(MQSendBean mqSendBean){
        Message message = new Message();
        message.setBody(gson.toJson(mqSendBean).getBytes());
        message.setTopic(TOPIC);
        message.setTags(mqSendBean.getTag().name());
        String messageId;
        try{
            SendResult sendResult = producer.send(message);
            messageId = sendResult.getMsgId();
        }catch (Exception e){
//            降级服务
            mqManager.process();
        }
    }

}

这个时候有同学就会问了,主播主播,你的降级确实很有东西,但是跨系统非自产自销的怎么办呢,你不能强制对方给你弄个接口吧?你还有方法吗?
有的兄弟,有的——可以用重试组件讲业务数据失败的记录在册,重试成功再删除数据

    public void send(MQSendBean mqSendBean){
        Message message = new Message();
        message.setBody(gson.toJson(mqSendBean).getBytes());
        message.setTopic(TOPIC);
        message.setTags(mqSendBean.getTag().name());
        String messageId;
        try{
            SendResult sendResult = producer.send(message);
            messageId = sendResult.getMsgId();
        }catch (Exception e){
//            降级服务
            RertyUtil.record()
        }
    }

但是兄弟,还是温馨提醒一句,重试不仅会增加系统复杂度,你还应该考虑一个问题
MQ是不是本身就有三次重试?你想想看,要是MQ本身有重试,你这个还是发送失败,这说明甚么?——出大问题了啊兄弟,MQ集群要炸了啊!重试还香吗?我看未必
于是我们经常用的手法可能更倾向于——上报日志

    public void send(MQSendBean mqSendBean){
        Message message = new Message();
        message.setBody(gson.toJson(mqSendBean).getBytes());
        message.setTopic(TOPIC);
        message.setTags(mqSendBean.getTag().name());
        String messageId;
        try{
            SendResult sendResult = producer.send(message);
            messageId = sendResult.getMsgId();
        }catch (Exception e){
//            降级服务
            LogUtil.log()
        }
    }

这个时候有小伙伴就会说了
主播主播,我们常说有熔断、限流,你怎么没有说呢?
不是主播不想说,主播接触的常是业务代码,所以熔断其实有业务不一致的风险的,so其实我们一般不会用
但是主播在MQ限流降级确实还有另外一点心得不过跟这个主题——线上故障关系不大了
请移步到XXXXX(还没写)去看看相关知识
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值