欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

pinpoint web报警机制算法解析

程序员文章站 2022-04-06 12:33:37
我们在使用pinpoint的报警功能的时候,发现如果持续一段时间内一直存在异常情况,但是并不是每一分钟都会接受到pinpoint的报警邮件,而是有一个时间间隔的,本文旨在分析其报警的策略算法。 ......

背景:

  见上一篇文章

  我们在使用pinpoint的报警功能的时候,发现如果持续一段时间内一直存在异常情况,但是并不是每一分钟都会接受到pinpoint的报警邮件,而是有一个时间间隔的,本文旨在分析其报警的策略算法。

相关类:

1)checkresult,该类代表了报警历史,是存储在数据库当中的。

该类与此算法有关的字段有3个,分别为detected,sequencecount,timingcount。

detected代表是否报警过,sequencecount代表已经进行检查的次数,timingcount代表第几次检查应该报警。

2)alarmchecker,该类代表了一次检查的结果,是在内存中的临时对象。

该类与此算法有关的字段有1个,分别为detected。

detected代表此次是否有异常情况

 

alarmchecker的detected字段和checkresult的detected字段含义稍有区别,请注意区分

算法步骤:

1.当alarmchecker的detected字段为true 的时候(此次有异常情况),则根据isturntosendalarm方法来判断此次是否应该报警:

1)检查checkresult报警历史中的detected来查看历史上是否报警过,如果没有,则返回true

2)如果detected == true,则代表历史上报过警,sequencecount和timingcount是否相差1,如果是则返回true,否则返回false

 

2.更新checkresult记录:

1)删除原先的记录

2)如果alarmchecker.detected == false,则插入一条“新”记录,detected为false,sequencecount为0,timingcount为1。

3)如果alarmchecker.detected == true,则插入一条“旧”记录,detected为true,sequencecount在原先的基础上+1,timingcount如果和sequencecount相等则在原先的基础上乘2再加1,否则不变。

 

源码:[现在看看源码会比较清晰了]

alarmwriter

package com.navercorp.pinpoint.web.alarm;

import java.util.list;
import java.util.map;

import org.springframework.batch.item.itemwriter;
import org.springframework.beans.factory.annotation.autowired;

import com.navercorp.pinpoint.web.alarm.checker.alarmchecker;
import com.navercorp.pinpoint.web.alarm.vo.checkerresult;
import com.navercorp.pinpoint.web.service.alarmservice;

/**
 * @author minwoo.jung
 */
public class alarmwriter implements itemwriter<alarmchecker> {

    @autowired(required = false)
    private alarmmessagesender alarmmessagesender = new emptymessagesender();

    @autowired
    private alarmservice alarmservice;

    @override
    public void write(list<? extends alarmchecker> checkers) throws exception {
        map<string, checkerresult> beforecheckerresults = alarmservice.selectbeforecheckerresults(checkers.get(0).getrule().getapplicationid());

        for (alarmchecker checker : checkers) {
            checkerresult beforecheckerresult = beforecheckerresults.get(checker.getrule().getcheckername());

            if (beforecheckerresult == null) {
                beforecheckerresult = new checkerresult(checker.getrule().getapplicationid(), checker.getrule().getcheckername(), false, 0, 1);
            }

            if (checker.isdetected()) {
                sendalarmmessage(beforecheckerresult, checker);
            }

            alarmservice.updatebeforecheckerresult(beforecheckerresult, checker);
        }
    }

    // 防止重复报警
    private void sendalarmmessage(checkerresult beforecheckerresult, alarmchecker checker) {
        if (isturntosendalarm(beforecheckerresult)) {
            if (checker.issmssend()) {
                alarmmessagesender.sendsms(checker, beforecheckerresult.getsequencecount() + 1);
            }
            if (checker.isemailsend()) {
                alarmmessagesender.sendemail(checker, beforecheckerresult.getsequencecount() + 1);
            }
        }

    }

    private boolean isturntosendalarm(checkerresult beforecheckerresult) {
        // 之前没报过警就报警
        if (!beforecheckerresult.isdetected()) {
            return true;
        }
        // 如果之前报过警,则延迟报警;检查sequencecount和timingcount是否相差1。
        int sequencecount = beforecheckerresult.getsequencecount() + 1;

        if (sequencecount == beforecheckerresult.gettimingcount()) {
            return true;
        }

        return false;
    }
}

  alarmservice.updatebeforecheckerresult方法

@override
    public void updatebeforecheckerresult(checkerresult beforecheckerresult, alarmchecker checker) {
        alarmdao.deletecheckerresult(beforecheckerresult);
        
        if (checker.isdetected()) {
            beforecheckerresult.setdetected(true);
            // 更新下次应该报警的时间点
            beforecheckerresult.incresecount();
            alarmdao.insertcheckerresult(beforecheckerresult);
        } else {
            alarmdao.insertcheckerresult(new checkerresult(checker.getrule().getapplicationid(), checker.getrule().getcheckername(), false, 0, 1));
        }
        
         
    }

  beforecheckerresult.incresecount()方法

// 延时报警,防止每分钟都报警,引起轰炸
    public void incresecount() {
        // sequencecount为检查的次数
        ++sequencecount;
        // timingcount代表检查次数达到timingcount则报警
        // 如果此次已经报警,则延迟下次报警的时间
        if (sequencecount == timingcount) {
            timingcount = sequencecount * 2 + 1;
        }
    }