pinpoint web報警機制算法解析


背景:

  見上一篇文章 https://www.cnblogs.com/langshiquan/p/9497464.html 

  我們在使用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,否則不變。

效果:

  實現了報警延遲功能,持續異常情況下,第1分鍾報警,接下來,第3分鍾報警(間隔2分鍾),接下來,第7分鍾報警(距離前一次間隔4分鍾)....

源碼:[現在看看源碼會比較清晰了]

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;
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM