監控平臺的設計缺陷

監控指標採集(WarningLog) -> 規則驗證 (WarningRuleRecord)-> 通知記錄(WarningEvent)

報警規則
報警的觸發條件和通知方式。

報警事件 WarningRuleRecord
系統每隔1分鐘,就會根據報警規則中設置的報警觸發條件,判斷指標是否觸發報警。如果觸發,則會生成一個報警事件記錄。

通知記錄 WarningEvent
報警事件生成之後,系統會根據報警規則中設置的報警生效時段和報警間隔,判斷是否發送報警通知(電話、短信、釘釘羣機器人)給您。如果發送,則會生成一個通知記錄。

閾值報警
當前指標的值和閾值實時比較,如果符合設定的閾值條件,則觸發報警。

1.0 監控平臺之前出過的問題

雖然 之前讓公元優化定時輪詢的執行線程池,理論上所有定時任務都會在同一個線程池的不同線程上-一定程度上解決了之前的告警事件延時問題。默認是所有定時輪詢都是一個線程執行。 導致告警事件延時。出現大量延時重複數據。

1.1 監控指標採集
WarningLog metric 收集表
type =1 業務上隊列積壓監控 (輪詢調用隊列服務,拉取)
type =2 來自隊列監控 ,(推送,這個目前只有一個指標,沒有插件開發收集指標問題。java這邊會開發收集tps ,rt 等指標插件,詳情請看https://www.jianshu.com/p/28d25a6637ff
type =3 來自採集器(拉取)
監控設計上拉取就有問題 ,70個線上指標就出現了線上指標延遲問題。如果有上萬個線上指標呢。

通過分佈式lock ,定時輪詢監控指標通過3種不同方式,進行收集批量寫入WarningLog 表 。

性能上 ,不管有多少pod , 同時執行的只有一個pod的一個線程池 。性能上,無擴展的能力 。
而且目前收集都採用的拉的方式,一旦某個服務不可用,會阻塞當前執行線程。收集的數據量很大的情況 ,必然會導致數據收集端的延時 。所以線上對接的業務指標還不是很多,大概60,70個。沒有服務metric 指標等,和以前公司幾十萬個服務監控指標差距還是很大的,目前作用其實也不大。

1.2 監控規則

監控規則採用 自定義 @Async 方式,執行規則將符合規則的告警數據插入告警規則表WarningRuleRecord中, @Async大量存在與j37代碼中。所有異步接口代碼都公用一個線程池 ,隨着未來規則越來越多,必然會存在着上一個監控規則輪詢沒有執行完 ,下個規則輪詢就開始的問題.隨着累積的加劇 ,後期必然會影響其他的異步方法調用。
目前線上已經出現了積壓情況。值得警惕

j37-51-6988d5667c-dtc22 | online | 10.66.1.207 | cn-zhangjiakou.10.63.97.203 | 線程池 async-service- 中隊列積壓任務數量爲 71

1.3 告警
通過告警規則找到對應告警規則記錄WarningRuleRecord,通過告警通知合併策略以及通知策略。下推通知WarningEvent給用戶
代碼規範真的蠻弱的 , 0,6 表示類別,狀態, 還是蠻難看懂的

      query.setIsDelete(0);
    query.setStatus(0);
    query.setCreateDate(beforeTime);
    query.setRuleId(warningRule.getId());
    query.setWarningServiceId(warningRule.getWarningServiceId());
    List<WarningEvent> eventList = eventMapper.queryByWarningServiceId(query);
    if (CollectionUtils.isNotEmpty(eventList)) {
        for (WarningEvent item : eventList) {
            WarningEventOperation eventOperation = new WarningEventOperation();
            eventOperation.setIsDelete(0);
            eventOperation.setEventId(item.getId());
            eventOperation.setType(6);

1.4 過期數據清除
雖然通過分佈式lock ,但依然會有多個pod 同時執行dataclean任務,這裏讓我不得不懷疑分佈式lock 有沒有作用。


從清除數據上可知 ,每天凌晨2點線上清除的數據在 16w 級別 ,數據量不大。

1.5 通知流程

下面是實現代碼

/**
 * 每天凌晨2:00清理數據
 */
@Scheduled(cron = "0 0 2 * * ?")
private void dataClean() {
    redisLockUtil.executeWithLock("data:clean:cron:Lock", () -> {
        // 定時清理主無效的(告警規則運行記錄)
        warningCronService.dataClean();
    });
}
/**
     * 整分鐘00秒運行
     */
    @Scheduled(cron = "0 */1 * * * ?")
    private void executeLogCollectCron() {
        redisLockUtil.executeWithLock("warning:Collect:Execute:Lock111", () -> {
            // 告警規則運行週期(整分鐘00秒運行)
            warningCronService.excute();

            //告警日誌數據採集器(週期性採集數據)
            warningCronService.executeLogCollect();

            //防止異步方法過快釋放分佈式鎖 (任務運行多次)
            waitReleaseLock(1);
        });
    }

    /**
     * 整分鐘00秒運行
     */
    @Scheduled(cron = "0 */1 * * * ?")
    private void executeLogCollectCron() {
        redisLockUtil.executeWithLock("warning:Collect:Execute:Lock111", () -> {
            // 告警規則運行週期(整分鐘00秒運行)
            warningCronService.excute();

            //告警日誌數據採集器(週期性採集數據)
            warningCronService.executeLogCollect();

            //防止異步方法過快釋放分佈式鎖 (任務運行多次)
            waitReleaseLock(1);
        });
    }

    /**
     * 整分鐘30秒運行
     */
    @Scheduled(cron = "30 */1 * * * ?")
    private void executeExcuteCron() {
        redisLockUtil.executeWithLock("warning:Excute:Execute:Lock", () -> {
            //每1分鐘通過接口調用,獲取隊列積壓數據&(記錄最大歷史積壓值)
            warningCronService.executeQueueWarning();
        });
    }

    /**
     * 每三十秒檢測是否有待接收事件需要發送消息(包括輪詢消息和合並後消息)
     */
    @Scheduled(cron = "0/30 * * * * ?")
    private void sendQueueMessage() {
        redisLockUtil.executeWithLock("send:Queue:Message", () -> {
            // 三十秒一次檢測隊列事件是否超過合併週期(超過週期就發送預警消息)
            warningCronService.sendQueueMessage();
            // 三十秒一次檢測普通事件是否超過合併週期(超過週期就發送預警消息)
            warningCronService.sendMessage();
            // 輪詢發送消息
            warningCronService.sendMoreMessage();
        });
    }

    /**
     * 每天凌晨2:00清理數據
     */
    @Scheduled(cron = "0 0 2 * * ?")
    private void dataClean() {
        redisLockUtil.executeWithLock("data:clean:cron:Lock", () -> {
            // 定時清理主無效的(告警規則運行記錄)
            warningCronService.dataClean();
        });
    }

    private void waitReleaseLock(int i) {
        try {
            Thread.sleep(i * 1000);
        } catch (Exception e) {
        }
    }

    /**
     * 從隊列裏面獲取
     */
    @Scheduled(cron = "0/30 * * * * ?")
    public void queueCollect() {
        if (!queueCollectFlag) {
            return;
        }
        redisLockUtil.executeWithLock(QUEUE_COLLECT_REDIS_KEY, () -> {
            warningCronService.exportLogFromQueue();
        });
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章